Skip to content

feat(eslint-plugin): [member-delimiter-style] Add an option 'multilineDetection' to treat types and interfaces as single line if the last member ends on the same line as the closing bracket #2970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 28, 2021
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
9 changes: 8 additions & 1 deletion packages/eslint-plugin/docs/rules/member-delimiter-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Config = BaseConfig & {
interface?: BaseConfig;
typeLiteral?: BaseConfig;
};
multilineDetection?: 'brackets' | 'last-member';
};
```

Expand All @@ -86,14 +87,20 @@ Default config:
"singleline": {
"delimiter": "semi",
"requireLast": false
}
},
"multilineDetection": "brackets"
}
```

`multiline` config only applies to multiline `interface`/`type` definitions.
`singleline` config only applies to single line `interface`/`type` definitions.
The two configs are entirely separate, and do not effect one another.

`multilineDetection` determines what counts as multiline

- `"brackets"` (default) any newlines in the type or interface make it multiline.
- `"last-member"` if the last member of the interface is on the same line as the last bracket, it is counted as a single line.

### `delimiter`

Accepts three values (or two for `singleline`):
Expand Down
19 changes: 17 additions & 2 deletions packages/eslint-plugin/src/rules/member-delimiter-style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Config = BaseOptions & {
typeLiteral?: BaseOptions;
interface?: BaseOptions;
};
multilineDetection?: 'brackets' | 'last-member';
};
type Options = [Config];
type MessageIds =
Expand Down Expand Up @@ -82,6 +83,9 @@ export default util.createRule<Options, MessageIds>({
},
additionalProperties: false,
},
multilineDetection: {
enum: ['brackets', 'last-member'],
},
}),
additionalProperties: false,
},
Expand All @@ -97,6 +101,7 @@ export default util.createRule<Options, MessageIds>({
delimiter: 'semi',
requireLast: false,
},
multilineDetection: 'brackets',
},
],
create(context, [options]) {
Expand Down Expand Up @@ -215,11 +220,21 @@ export default util.createRule<Options, MessageIds>({
function checkMemberSeparatorStyle(
node: TSESTree.TSInterfaceBody | TSESTree.TSTypeLiteral,
): void {
const isSingleLine = node.loc.start.line === node.loc.end.line;

const members =
node.type === AST_NODE_TYPES.TSInterfaceBody ? node.body : node.members;

let isSingleLine = node.loc.start.line === node.loc.end.line;
if (
options.multilineDetection === 'last-member' &&
!isSingleLine &&
members.length > 0
) {
const lastMember = members[members.length - 1];
if (lastMember.loc.end.line === node.loc.end.line) {
isSingleLine = true;
}
}

const typeOpts =
node.type === AST_NODE_TYPES.TSInterfaceBody
? interfaceOptions
Expand Down
165 changes: 165 additions & 0 deletions packages/eslint-plugin/tests/rules/member-delimiter-style.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,75 @@ type Bar = {
},
],
},
{
code: `
type Foo = {a: {
b: true;
}};
`,
options: [
{
multilineDetection: 'last-member',
},
],
},
`
type Foo = {a: {
b: true;
};};
`,
{
code: `
type Foo = {a: {
b: true;
};};
`,
options: [
{
multilineDetection: 'brackets',
},
],
},
{
code: `
type Foo = {
a: {
b: true;
};
};
`,
options: [
{
multilineDetection: 'last-member',
},
],
},
{
code: `
type Foo = {a: {
b: true;
};};
`,
options: [
{
singleline: { delimiter: 'semi', requireLast: true },
multilineDetection: 'last-member',
},
],
},
{
code: `
type Foo = {

};
`,
options: [
{
singleline: { delimiter: 'semi', requireLast: true },
multilineDetection: 'last-member',
},
],
},

{
code: `
Expand Down Expand Up @@ -3365,5 +3434,101 @@ type Foo = {
},
],
},
{
code: `
type Foo = {a: {
b: true;
};};
`,
output: `
type Foo = {a: {
b: true;
}};
`,
options: [
{
multilineDetection: 'last-member',
},
],
errors: [
{
messageId: 'unexpectedSemi',
line: 4,
column: 3,
},
],
},
{
code: `
type Foo = {a: {
b: true;
}};
`,
output: `
type Foo = {a: {
b: true;
};};
`,
errors: [
{
messageId: 'expectedSemi',
line: 4,
column: 2,
},
],
},
{
code: `
type Foo = {
a: {
b: true;
}
};
`,
output: `
type Foo = {
a: {
b: true;
};
};
`,
options: [
{
multilineDetection: 'last-member',
},
],
errors: [
{
messageId: 'expectedSemi',
line: 5,
column: 4,
},
],
},
{
code: `
type Foo = {a: {
b: true;
}};
`,
output: `
type Foo = {a: {
b: true;
};};
`,
options: [
{
singleline: { delimiter: 'semi', requireLast: true },
multilineDetection: 'last-member',
},
],
errors: [
{
messageId: 'expectedSemi',
line: 4,
column: 2,
},
],
},
],
});