Skip to content
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

feat: Object curly newline #490

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"gitdown": "include", "file": "./rules/no-types-missing-file-annotation.md"}
{"gitdown": "include", "file": "./rules/no-unused-expressions.md"}
{"gitdown": "include", "file": "./rules/no-weak-types.md"}
{"gitdown": "include", "file": "./rules/object-type-curly-newline.md"}
{"gitdown": "include", "file": "./rules/object-type-curly-spacing.md"}
{"gitdown": "include", "file": "./rules/object-type-delimiter.md"}
{"gitdown": "include", "file": "./rules/quotes.md"}
Expand Down
15 changes: 15 additions & 0 deletions .README/rules/object-type-curly-newline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### `object-type-curly-newline`

_The `--fix` option on the command line automatically fixes problems reported by this rule._

This rule enforce consistent line breaks after opening and before closing braces of type objects.

#### Options

The rule has a string option:

* `"never"`: disallows multiline type objects.
* `"always"`: requires multiline type objects.
* `"multiline"`(default): acts as `never` until there is a multiline, then acts as `always`

<!-- assertions objectTypeCurlyNewline -->
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import noUnusedExpressions from './rules/noUnusedExpressions';
import noWeakTypes from './rules/noWeakTypes';
import noInternalFlowType from './rules/noInternalFlowType';
import noMixed from './rules/noMixed';
import objectTypeCurlyNewline from './rules/objectTypeCurlyNewline';
import objectTypeCurlySpacing from './rules/objectTypeCurlySpacing';
import objectTypeDelimiter from './rules/objectTypeDelimiter';
import quotes from './rules/quotes';
Expand Down Expand Up @@ -67,6 +68,7 @@ const rules = {
'no-types-missing-file-annotation': noTypesMissingFileAnnotation,
'no-unused-expressions': noUnusedExpressions,
'no-weak-types': noWeakTypes,
'object-type-curly-newline': objectTypeCurlyNewline,
'object-type-curly-spacing': objectTypeCurlySpacing,
'object-type-delimiter': objectTypeDelimiter,
quotes,
Expand Down
88 changes: 88 additions & 0 deletions src/rules/objectTypeCurlyNewline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {spacingFixers} from '../utilities';

const schema = [
{
enum: ['always', 'never', 'multiline'],
type: 'string',
},
];

const meta = {
fixable: 'code',
};

const create = (context) => {
const option = context?.options[0] ?? 'multiline';

return {
ObjectTypeAnnotation (node) {
const {
properties,
} = node;

if (properties.length === 0) {
return;
}

const sourceCode = context.getSourceCode();

if (option === 'always' || option === 'multiline') {
// If option is multiline act as never but if there are any multi lines
// act as always
if (option === 'multiline' && node.loc.start.line === node.loc.end.line) {
return;
}

if (properties[0].loc.start.line === node.loc.start.line) {
context.report({
fix: (fixer) => {
return fixer.insertTextAfter(
sourceCode.getFirstToken(node),
'\n',
);
},
message: 'There should be a newline after opening curly brace',
node,
});
}

if (properties[properties.length - 1].loc.end.line === node.loc.end.line) {
context.report({
fix: (fixer) => {
return fixer.insertTextBefore(
sourceCode.getLastToken(node),
'\n',
);
},
message: 'There should be a newline before closing curly brace',
node,
});
}
} else if (option === 'never') {
if (properties[0].loc.start.line !== node.loc.start.line) {
const openBrace = sourceCode.getFirstToken(node);
context.report({
fix: spacingFixers.stripSpacesAfter(openBrace, 1),
message: 'There should not be a newline after opening curly brace',
node,
});
}

if (properties[properties.length - 1].loc.end.line !== node.loc.end.line) {
const closingBrace = sourceCode.getLastToken(node);
context.report({
fix: spacingFixers.stripSpacesBefore(closingBrace, 1),
message: 'There should not be a newline before closing curly brace',
node,
});
}
}
},
};
};

export default {
create,
meta,
schema,
};
93 changes: 93 additions & 0 deletions tests/rules/assertions/objectTypeCurlyNewline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export default {
invalid: [
// Never
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have some tests when there object has multiple properties

Copy link
Contributor Author

@Brianzchen Brianzchen Aug 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I can, just to note though this rule does not cater to multi-lining multiple properties, that'll be handled by a separate rule hopefully in the near future just like standard objects https://eslint.org/docs/rules/object-property-newline.

Edit: found some bug behaviour, will fix

code: 'type obj = { "foo": "bar"\n}',
errors: [
{message: 'There should not be a newline before closing curly brace'},
],
options: ['never'],
output: 'type obj = { "foo": "bar"}',
},
{
code: 'type obj = {\n"foo": "bar" }',
errors: [
{message: 'There should not be a newline after opening curly brace'},
],
options: ['never'],
output: 'type obj = {"foo": "bar" }',
},
{
code: 'type obj = {\n"foo": "bar"\n}',
errors: [
{message: 'There should not be a newline after opening curly brace'},
{message: 'There should not be a newline before closing curly brace'},
],
options: ['never'],
output: 'type obj = {"foo": "bar"}',
},

// Always
{
code: 'type obj = {"foo": "bar"\n}',
errors: [
{message: 'There should be a newline after opening curly brace'},
],
options: ['always'],
output: 'type obj = {\n"foo": "bar"\n}',
},
{
code: 'type obj = {\n"foo": "bar"}',
errors: [
{message: 'There should be a newline before closing curly brace'},
],
options: ['always'],
output: 'type obj = {\n"foo": "bar"\n}',
},
{
code: 'type obj = {"foo": "bar"}',
errors: [
{message: 'There should be a newline after opening curly brace'},
{message: 'There should be a newline before closing curly brace'},
],
options: ['always'],
output: 'type obj = {\n"foo": "bar"\n}',
},

// Multiline
{
code: 'type obj = { "foo": "bar"\n}',
errors: [
{message: 'There should be a newline after opening curly brace'},
],
options: ['multiline'],
output: 'type obj = {\n "foo": "bar"\n}',
},
{
code: 'type obj = {\n"foo": "bar"}',
errors: [
{message: 'There should be a newline before closing curly brace'},
],
options: ['multiline'],
output: 'type obj = {\n"foo": "bar"\n}',
},
],
valid: [
{
code: 'type obj = { test: a }',
options: ['never'],
},
{
code: 'type obj = {\ntest: a\n}',
options: ['always'],
},
{
code: 'type obj = { test: a }',
options: ['multiline'],
},
{
code: 'type obj = {\ntest: a\n}',
options: ['multiline'],
},
],
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const reportingRules = [
'no-weak-types',
'no-internal-flow-type',
'no-mixed',
'object-type-curly-newline',
'object-type-curly-spacing',
'object-type-delimiter',
'quotes',
Expand Down