Skip to content

Commit ae3b724

Browse files
authored
feat: allow breaking imports/exports when more than one (#617)
1 parent 57eb042 commit ae3b724

10 files changed

+120
-20
lines changed

deployment/schema.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,14 +284,17 @@
284284
},
285285
"forceMultiLineSpecifiers": {
286286
"description": "If code import/export specifiers should be forced to be on multiple lines.",
287-
"type": "boolean",
288-
"default": false,
287+
"type": "string",
288+
"default": "never",
289289
"oneOf": [{
290-
"const": true,
290+
"const": "always",
291291
"description": ""
292292
}, {
293-
"const": false,
293+
"const": "never",
294294
"description": ""
295+
}, {
296+
"const": "onlyWhenMultiple",
297+
"description": "Force multiple lines only if importing more than one thing."
295298
}]
296299
},
297300
"sortOrder": {

src/configuration/builder.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,12 @@ impl ConfigurationBuilder {
759759

760760
/* force multi line specifiers */
761761

762-
pub fn export_declaration_force_multi_line(&mut self, value: bool) -> &mut Self {
763-
self.insert("exportDeclaration.forceMultiLine", value.into())
762+
pub fn export_declaration_force_multi_line(&mut self, value: ForceMultiLine) -> &mut Self {
763+
self.insert("exportDeclaration.forceMultiLine", value.to_string().into())
764764
}
765765

766-
pub fn import_declaration_force_multi_line(&mut self, value: bool) -> &mut Self {
767-
self.insert("importDeclaration.forceMultiLine", value.into())
766+
pub fn import_declaration_force_multi_line(&mut self, value: ForceMultiLine) -> &mut Self {
767+
self.insert("importDeclaration.forceMultiLine", value.to_string().into())
768768
}
769769

770770
/* member spacing */
@@ -1220,8 +1220,8 @@ mod tests {
12201220
.export_declaration_force_single_line(true)
12211221
.import_declaration_force_single_line(true)
12221222
/* force multi line specifiers */
1223-
.export_declaration_force_multi_line(true)
1224-
.import_declaration_force_multi_line(true)
1223+
.export_declaration_force_multi_line(ForceMultiLine::Always)
1224+
.import_declaration_force_multi_line(ForceMultiLine::Always)
12251225
/* space settings */
12261226
.binary_expression_space_surrounding_bitwise_and_arithmetic_operator(true)
12271227
.comment_line_force_space_after_slashes(false)

src/configuration/resolve_config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ pub fn resolve_config(config: ConfigKeyMap, global_config: &GlobalConfiguration)
254254
import_declaration_force_single_line: get_value(&mut config, "importDeclaration.forceSingleLine", false, &mut diagnostics),
255255
export_declaration_force_single_line: get_value(&mut config, "exportDeclaration.forceSingleLine", false, &mut diagnostics),
256256
/* force multi line specifiers */
257-
import_declaration_force_multi_line: get_value(&mut config, "importDeclaration.forceMultiLine", false, &mut diagnostics),
258-
export_declaration_force_multi_line: get_value(&mut config, "exportDeclaration.forceMultiLine", false, &mut diagnostics),
257+
import_declaration_force_multi_line: get_value(&mut config, "importDeclaration.forceMultiLine", ForceMultiLine::Never, &mut diagnostics),
258+
export_declaration_force_multi_line: get_value(&mut config, "exportDeclaration.forceMultiLine", ForceMultiLine::Never, &mut diagnostics),
259259
/* space settings */
260260
binary_expression_space_surrounding_bitwise_and_arithmetic_operator: get_value(
261261
&mut config,

src/configuration/types.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ pub enum TrailingCommas {
5757

5858
generate_str_to_from![TrailingCommas, [Always, "always"], [Never, "never"], [OnlyMultiLine, "onlyMultiLine"]];
5959

60+
/// Force multilines possibilities.
61+
#[derive(Clone, PartialEq, Copy, Serialize, Deserialize)]
62+
#[serde(rename_all = "camelCase")]
63+
pub enum ForceMultiLine {
64+
/// Multiline imports/exports should not be forced.
65+
Never,
66+
/// Always force multiline imports/exports.
67+
Always,
68+
/// Mulitline imports/exports should be forced only when importing/exporting multiple items.
69+
OnlyWhenMultiple,
70+
}
71+
72+
generate_str_to_from![ForceMultiLine, [Always, "always"], [Never, "never"], [OnlyWhenMultiple, "onlyWhenMultiple"]];
73+
6074
/// Where to place the opening brace.
6175
#[derive(Clone, PartialEq, Copy, Serialize, Deserialize)]
6276
#[serde(rename_all = "camelCase")]
@@ -541,9 +555,9 @@ pub struct Configuration {
541555
pub export_declaration_force_single_line: bool,
542556
/* force multi line specifiers */
543557
#[serde(rename = "exportDeclaration.forceMultiLine")]
544-
pub export_declaration_force_multi_line: bool,
558+
pub export_declaration_force_multi_line: ForceMultiLine,
545559
#[serde(rename = "importDeclaration.forceMultiLine")]
546-
pub import_declaration_force_multi_line: bool,
560+
pub import_declaration_force_multi_line: ForceMultiLine,
547561

548562
/* use space separator */
549563
#[serde(rename = "binaryExpression.spaceSurroundingBitwiseAndArithmeticOperator")]

src/generation/generate.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,10 +1033,16 @@ fn gen_export_named_decl<'a>(node: &NamedExport<'a>, context: &mut Context<'a>)
10331033
}
10341034

10351035
let force_single_line = context.config.export_declaration_force_single_line && !contains_line_or_multiline_comment(node.into(), context.program);
1036+
1037+
let force_multi_line = !force_single_line
1038+
&& ((context.config.export_declaration_force_multi_line == ForceMultiLine::Always)
1039+
|| (named_exports.len() > 1 && context.config.export_declaration_force_multi_line == ForceMultiLine::OnlyWhenMultiple));
1040+
10361041
let should_single_line = force_single_line
10371042
|| (default_export.is_none()
10381043
&& namespace_export.is_none()
1039-
&& (named_exports.len() <= 1 && !context.config.export_declaration_force_multi_line)
1044+
&& !force_multi_line
1045+
&& (named_exports.len() <= 1 && context.config.export_declaration_force_multi_line == ForceMultiLine::Never)
10401046
&& node.start_line_fast(context.program) == node.end_line_fast(context.program));
10411047

10421048
// generate
@@ -1055,7 +1061,7 @@ fn gen_export_named_decl<'a>(node: &NamedExport<'a>, context: &mut Context<'a>)
10551061
parent: node.into(),
10561062
specifiers: named_exports.into_iter().map(|x| x.into()).collect(),
10571063
force_single_line,
1058-
force_multi_line_specifiers: context.config.export_declaration_force_multi_line,
1064+
force_multi_line_specifiers: force_multi_line,
10591065
},
10601066
context,
10611067
));
@@ -1218,11 +1224,17 @@ fn gen_import_decl<'a>(node: &ImportDecl<'a>, context: &mut Context<'a>) -> Prin
12181224
}
12191225

12201226
let force_single_line = context.config.import_declaration_force_single_line && !contains_line_or_multiline_comment(node.into(), context.program);
1227+
1228+
let force_multi_line = context.config.import_declaration_force_multi_line == ForceMultiLine::Always
1229+
|| (named_imports.len() > 1 && context.config.import_declaration_force_multi_line == ForceMultiLine::OnlyWhenMultiple);
1230+
12211231
let should_single_line = force_single_line
12221232
|| (default_import.is_none()
12231233
&& namespace_import.is_none()
1224-
&& (named_imports.len() <= 1 && !context.config.import_declaration_force_multi_line)
1234+
&& !force_multi_line
1235+
&& (named_imports.len() <= 1 && context.config.import_declaration_force_multi_line == ForceMultiLine::Never)
12251236
&& node.start_line_fast(context.program) == node.end_line_fast(context.program));
1237+
12261238
let has_named_imports = !named_imports.is_empty() || {
12271239
let from_keyword = context.token_finder.get_previous_token_if_from_keyword(node.src);
12281240
if let Some(from_keyword) = from_keyword {
@@ -1267,7 +1279,7 @@ fn gen_import_decl<'a>(node: &ImportDecl<'a>, context: &mut Context<'a>) -> Prin
12671279
parent: node.into(),
12681280
specifiers: named_imports.into_iter().map(|x| x.into()).collect(),
12691281
force_single_line,
1270-
force_multi_line_specifiers: context.config.import_declaration_force_multi_line,
1282+
force_multi_line_specifiers: force_multi_line,
12711283
},
12721284
context,
12731285
));

tests/specs/declarations/export/ExportDeclaration_ForceMultiLine_True.txt renamed to tests/specs/declarations/export/ExportDeclaration_ForceMultiLine_Always.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
~~ exportDeclaration.forceMultiLine: true, lineWidth: 40 ~~
1+
~~ exportDeclaration.forceMultiLine: always, lineWidth: 40 ~~
22
== should always add a new line between exports ==
33
export { testing, a, b, c, d, e } from "./test.ts";
44
export { testing, a, b, c, d, e // test
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
~~ exportDeclaration.forceMultiLine: onlyWhenMultiple, lineWidth: 40 ~~
2+
== should never add a new line between exports ==
3+
export { testing, a, b, c, d, e } from "./test.ts";
4+
export { testing, a, b, c, d, e // test
5+
} from "./test.ts";
6+
export { a, b, c, d, e /* this is ok though testing testing */ } from "./test.ts";
7+
export { a, b, c, d, e /* and
8+
not ok */ } from "./test.ts";
9+
10+
[expect]
11+
export {
12+
a,
13+
b,
14+
c,
15+
d,
16+
e,
17+
testing,
18+
} from "./test.ts";
19+
export {
20+
a,
21+
b,
22+
c,
23+
d,
24+
e, // test
25+
testing,
26+
} from "./test.ts";
27+
export {
28+
a,
29+
b,
30+
c,
31+
d,
32+
e, /* this is ok though testing testing */
33+
} from "./test.ts";
34+
export {
35+
a,
36+
b,
37+
c,
38+
d,
39+
e, /* and
40+
not ok */
41+
} from "./test.ts";
42+
43+
== should not collapse a single-line one ==
44+
export { a } from "./test.ts";
45+
export { b } from "./test.ts";
46+
47+
[expect]
48+
export { a } from "./test.ts";
49+
export { b } from "./test.ts";

tests/specs/declarations/import/ImportDeclaration_ForceMultiLine.txt renamed to tests/specs/declarations/import/ImportDeclaration_ForceMultiLine_Always.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
~~ importDeclaration.forceMultiLine: true, lineWidth: 40 ~~
1+
~~ importDeclaration.forceMultiLine: always, lineWidth: 40 ~~
22
== should always add a new line between ==
33
import { testing, a, b, c, d, e } from "./test.ts";
44
import { testing, a, b, c, d, e // test
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
~~ importDeclaration.forceMultiLine: never, lineWidth: 40 ~~
2+
== should never add a new line between ==
3+
import { a, b } from "./test.ts";
4+
5+
[expect]
6+
import { a, b } from "./test.ts";
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
~~ importDeclaration.forceMultiLine: onlyWhenMultiple, lineWidth: 40 ~~
2+
== should break imports when more than one ==
3+
import { a, b } from "./test.ts";
4+
5+
[expect]
6+
import {
7+
a,
8+
b,
9+
} from "./test.ts";
10+
11+
== should not break single-line imports ==
12+
import { a } from "./test.ts";
13+
14+
15+
[expect]
16+
import { a } from "./test.ts";

0 commit comments

Comments
 (0)