Preserve blank lines inside of objects (#606)

We already preserve blank lines inside of classes but not objects. It's still very common to have objects that represent classes (React.createClass) and having the same behavior there seems like a good idea. It does make the snapshot tests look better!

Fixes #554
master
Christopher Chedeau 2017-02-09 08:08:58 -08:00 committed by James Long
parent 0287cadc62
commit 6632b95497
12 changed files with 57 additions and 3 deletions

View File

@ -600,13 +600,19 @@ function genericPrintNoParens(path, options, print) {
fields.push("properties"); fields.push("properties");
var i = 0;
var props = []; var props = [];
let separatorParts = [];
fields.forEach(function(field) { fields.forEach(function(field) {
path.each( path.each(
function(childPath) { function(childPath) {
props.push(concat(separatorParts));
props.push(group(print(childPath))); props.push(group(print(childPath)));
separatorParts = [separator, line];
if (util.isNextLineEmpty(options.originalText, childPath.getValue())) {
separatorParts.push(hardline);
}
}, },
field field
); );
@ -639,7 +645,7 @@ function genericPrintNoParens(path, options, print) {
options.tabWidth, options.tabWidth,
concat([ concat([
options.bracketSpacing ? line : softline, options.bracketSpacing ? line : softline,
join(concat([separator, line]), props) concat(props)
]) ])
), ),
ifBreak(canHaveTrailingComma && options.trailingComma ? "," : ""), ifBreak(canHaveTrailingComma && options.trailingComma ? "," : ""),

View File

@ -124,7 +124,7 @@ function skip(chars) {
const skipWhitespace = skip(/\s/); const skipWhitespace = skip(/\s/);
const skipSpaces = skip(" \t"); const skipSpaces = skip(" \t");
const skipToLineEnd = skip("; \t"); const skipToLineEnd = skip(",; \t");
const skipEverythingButNewLine = skip(/[^\r\n]/); const skipEverythingButNewLine = skip(/[^\r\n]/);
function skipInlineComment(text, index) { function skipInlineComment(text, index) {

View File

@ -81,6 +81,7 @@ module.exports = {
iTakeAString: function(name: string): number { iTakeAString: function(name: string): number {
return 42; return 42;
}, },
bar: function(): number { bar: function(): number {
return 42; return 42;
} }

View File

@ -210,29 +210,35 @@ var obj = {
get goodGetterWithAnnotation(): number { get goodGetterWithAnnotation(): number {
return 4; return 4;
}, },
set goodSetterNoAnnotation(x) { set goodSetterNoAnnotation(x) {
z = x; z = x;
}, },
set goodSetterWithAnnotation(x: number) { set goodSetterWithAnnotation(x: number) {
z = x; z = x;
}, },
get propWithMatchingGetterAndSetter(): number { get propWithMatchingGetterAndSetter(): number {
return 4; return 4;
}, },
set propWithMatchingGetterAndSetter(x: number) {}, set propWithMatchingGetterAndSetter(x: number) {},
// The getter and setter need not have the same type // The getter and setter need not have the same type
get propWithSubtypingGetterAndSetter(): ?number { get propWithSubtypingGetterAndSetter(): ?number {
return 4; return 4;
}, // OK }, // OK
set propWithSubtypingGetterAndSetter(x: number) {}, set propWithSubtypingGetterAndSetter(x: number) {},
set propWithSubtypingGetterAndSetterReordered(x: number) {}, // OK set propWithSubtypingGetterAndSetterReordered(x: number) {}, // OK
get propWithSubtypingGetterAndSetterReordered(): ?number { get propWithSubtypingGetterAndSetterReordered(): ?number {
return 4; return 4;
}, },
get exampleOfOrderOfGetterAndSetter(): A { get exampleOfOrderOfGetterAndSetter(): A {
return new A(); return new A();
}, },
set exampleOfOrderOfGetterAndSetter(x: B) {}, set exampleOfOrderOfGetterAndSetter(x: B) {},
set exampleOfOrderOfGetterAndSetterReordered(x: B) {}, set exampleOfOrderOfGetterAndSetterReordered(x: B) {},
get exampleOfOrderOfGetterAndSetterReordered(): A { get exampleOfOrderOfGetterAndSetterReordered(): A {
return new A(); return new A();

View File

@ -95,18 +95,21 @@ var Foo = {
// missing arg annotation // missing arg annotation
return arg; return arg;
}, },
b: function(arg) { b: function(arg) {
// missing arg annotation // missing arg annotation
return { return {
bar: arg bar: arg
}; };
}, },
c: function(arg: string) { c: function(arg: string) {
// no return annotation required // no return annotation required
return { return {
bar: arg bar: arg
}; };
}, },
d: function( d: function(
arg: string arg: string
): { ): {
@ -116,6 +119,7 @@ var Foo = {
bar: arg bar: arg
}; };
}, },
// return type annotation may be omitted, but if so, input positions on // return type annotation may be omitted, but if so, input positions on
// observed return type (e.g. param types in a function type) must come // observed return type (e.g. param types in a function type) must come
// from annotations // from annotations
@ -125,6 +129,7 @@ var Foo = {
return x; return x;
}; };
}, },
// ...if the return type is annotated explicitly, this is unnecessary // ...if the return type is annotated explicitly, this is unnecessary
f: function(arg: string): (x: number) => number { f: function(arg: string): (x: number) => number {
return function(x) { return function(x) {
@ -136,10 +141,13 @@ var Foo = {
var Bar = { var Bar = {
a: Foo.a(\"Foo\"), // no annotation required a: Foo.a(\"Foo\"), // no annotation required
// object property types are inferred, so make sure that this doesn\'t cause // object property types are inferred, so make sure that this doesn\'t cause
// us to also infer the parameter\'s type. // us to also infer the parameter\'s type.
b: Foo.b(\"bar\"), // no annotation required b: Foo.b(\"bar\"), // no annotation required
c: Foo.c(\"bar\"), // no annotation required c: Foo.c(\"bar\"), // no annotation required
d: Foo.d(\"bar\") // no annotation required d: Foo.d(\"bar\") // no annotation required
}; };

View File

@ -79,12 +79,15 @@ var App = React.createClass({
getDefaultProps: function(): { y: string } { getDefaultProps: function(): { y: string } {
return { y: \"\" }; // infer props.y: string return { y: \"\" }; // infer props.y: string
}, },
getInitialState: function() { getInitialState: function() {
return { z: 0 }; // infer state.z: number return { z: 0 }; // infer state.z: number
}, },
handler: function() { handler: function() {
this.setState({ z: 42 }); // ok this.setState({ z: 42 }); // ok
}, },
render: function() { render: function() {
var x = this.props.x; var x = this.props.x;
var y = this.props.y; var y = this.props.y;

View File

@ -67,6 +67,7 @@ var FeedUFI = React.createClass({
<UFILikeCount className=\"\" key=\"\" feedback={feedback} permalink=\"\" /> <UFILikeCount className=\"\" key=\"\" feedback={feedback} permalink=\"\" />
); );
}, },
render: function(): ?React.Element<any> { render: function(): ?React.Element<any> {
return <div />; return <div />;
} }
@ -130,6 +131,7 @@ var UFILikeCount = React.createClass({
permalink: React.PropTypes.string, permalink: React.PropTypes.string,
feedback: React.PropTypes.object.isRequired feedback: React.PropTypes.object.isRequired
}, },
render: function(): ?React.Element<any> { render: function(): ?React.Element<any> {
return <div />; return <div />;
} }
@ -337,22 +339,29 @@ var FooLegacy = React.createClass({
propTypes: { propTypes: {
x: React.PropTypes.number.isRequired x: React.PropTypes.number.isRequired
}, },
getDefaultProps(): DefaultProps { getDefaultProps(): DefaultProps {
return {}; return {};
}, },
statics: { statics: {
bar(): void {} bar(): void {}
}, },
qux(): void { qux(): void {
var _: string = this.props.x; var _: string = this.props.x;
}, },
getInitialState(): { y: string } { getInitialState(): { y: string } {
return { y: \"\" }; return { y: \"\" };
}, },
setState(o: { y_: string }): void {}, setState(o: { y_: string }): void {},
componentDidMount(): void { componentDidMount(): void {
this.is_mounted = true; this.is_mounted = true;
}, },
componentWillReceiveProps(nextProps: Object, nextContext: any): void { componentWillReceiveProps(nextProps: Object, nextContext: any): void {
this.qux(); this.qux();
} }
@ -452,6 +461,7 @@ var C = React.createClass({
z: React.PropTypes.number z: React.PropTypes.number
}, },
replaceProps(props: {}) {}, replaceProps(props: {}) {},
getDefaultProps(): { z: number } { getDefaultProps(): { z: number } {
return { z: 0 }; return { z: 0 };
}, },
@ -558,9 +568,11 @@ var TestProps = React.createClass({
x: React.PropTypes.string, x: React.PropTypes.string,
z: React.PropTypes.number z: React.PropTypes.number
}, },
getDefaultProps: function() { getDefaultProps: function() {
return { x: \"\", y: 0 }; return { x: \"\", y: 0 };
}, },
test: function() { test: function() {
var a: number = this.props.x; // error var a: number = this.props.x; // error
var b: string = this.props.y; // error var b: string = this.props.y; // error
@ -688,12 +700,14 @@ var TestProps = React.createClass({
object_rec: React.PropTypes.object.isRequired, object_rec: React.PropTypes.object.isRequired,
string: React.PropTypes.string, string: React.PropTypes.string,
string_rec: React.PropTypes.string.isRequired, string_rec: React.PropTypes.string.isRequired,
any: React.PropTypes.any, any: React.PropTypes.any,
any_rec: React.PropTypes.any.isRequired, any_rec: React.PropTypes.any.isRequired,
element: React.PropTypes.element, element: React.PropTypes.element,
element_rec: React.PropTypes.element.isRequired, element_rec: React.PropTypes.element.isRequired,
node: React.PropTypes.node, node: React.PropTypes.node,
node_rec: React.PropTypes.node.isRequired, node_rec: React.PropTypes.node.isRequired,
arrayOf: React.PropTypes.arrayOf(React.PropTypes.string), arrayOf: React.PropTypes.arrayOf(React.PropTypes.string),
arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
instanceOf: React.PropTypes.instanceOf(Object), instanceOf: React.PropTypes.instanceOf(Object),
@ -718,6 +732,7 @@ var TestProps = React.createClass({
foo: React.PropTypes.string, foo: React.PropTypes.string,
bar: React.PropTypes.number bar: React.PropTypes.number
}).isRequired, }).isRequired,
// And do something bad here // And do something bad here
bad_one: React.PropTypes.imaginaryType, bad_one: React.PropTypes.imaginaryType,
bad_two: React.PropTypes.string.inRequired bad_two: React.PropTypes.string.inRequired
@ -840,6 +855,7 @@ var ReactClass = React.createClass({
getInitialState: function(): State { getInitialState: function(): State {
return { bar: null }; return { bar: null };
}, },
render: function(): any { render: function(): any {
// Any state access here seems to make state any // Any state access here seems to make state any
this.state; this.state;
@ -919,6 +935,7 @@ var TestState = React.createClass({
x: \"\" x: \"\"
}; };
}, },
test: function() { test: function() {
var a: number = this.state.x; // error var a: number = this.state.x; // error
@ -951,6 +968,7 @@ var C = React.createClass({
getInitialState: function() { getInitialState: function() {
return { x: 0 }; return { x: 0 };
}, },
render() { render() {
this.setState({ y: 0 }); this.setState({ y: 0 });
return <div>{this.state.z}</div>; return <div>{this.state.z}</div>;

View File

@ -65,6 +65,7 @@ var x4: number = \"\".split(/pattern/)[0];
declare class C { declare class C {
foo(x: number): number, foo(x: number): number,
foo(x: string): string, foo(x: string): string,
bar(x: { a: number }): number, bar(x: { a: number }): number,
bar(x: { a: string }): string bar(x: { a: string }): string
} }

View File

@ -271,6 +271,7 @@ var React = React.createClass({
return \"Alice\"; return \"Alice\";
} }
}, },
render() { render() {
// But this never errored // But this never errored
return <div id={this.props.name} />; return <div id={this.props.name} />;

View File

@ -34,6 +34,7 @@ var HelloLocal = React.createClass({
propTypes: { propTypes: {
name: React.PropTypes.string.isRequired name: React.PropTypes.string.isRequired
}, },
render: function(): React.Element<*> { render: function(): React.Element<*> {
return <div>{this.props.name}</div>; return <div>{this.props.name}</div>;
} }
@ -77,6 +78,7 @@ var Hello = React.createClass({
propTypes: { propTypes: {
name: React.PropTypes.string.isRequired name: React.PropTypes.string.isRequired
}, },
render: function(): React.Element<*> { render: function(): React.Element<*> {
return <div>{this.props.name}</div>; return <div>{this.props.name}</div>;
} }

View File

@ -33,6 +33,7 @@ export const X = {
returnsATuple: function(): [number, number] { returnsATuple: function(): [number, number] {
return [1, 2]; return [1, 2];
}, },
test: function() { test: function() {
let [a, b] = this.returnsATuple(); let [a, b] = this.returnsATuple();
} }

View File

@ -63,22 +63,29 @@ declare class Promise<R> {
reject: (error?: any) => void reject: (error?: any) => void
) => void ) => void
): void, ): void,
then<U>( then<U>(
onFulfill?: ?(value: R) => Promise<U> | ?U, onFulfill?: ?(value: R) => Promise<U> | ?U,
onReject?: ?(error: any) => Promise<U> | ?U onReject?: ?(error: any) => Promise<U> | ?U
): Promise<U>, ): Promise<U>,
done<U>( done<U>(
onFulfill?: ?(value: R) => void, onFulfill?: ?(value: R) => void,
onReject?: ?(error: any) => void onReject?: ?(error: any) => void
): void, ): void,
catch<U>(onReject?: (error: any) => ?Promise<U> | U): Promise<U>, catch<U>(onReject?: (error: any) => ?Promise<U> | U): Promise<U>,
static resolve<T>(object?: Promise<T> | T): Promise<T>, static resolve<T>(object?: Promise<T> | T): Promise<T>,
static reject<T>(error?: any): Promise<T>, static reject<T>(error?: any): Promise<T>,
// Non-standard APIs // Non-standard APIs
finally<U>(onSettled?: ?(value: any) => Promise<U> | U): Promise<U>, finally<U>(onSettled?: ?(value: any) => Promise<U> | U): Promise<U>,
static cast<T>(object?: T): Promise<T>, static cast<T>(object?: T): Promise<T>,
static all<T>(promises: Array<?Promise<T> | T>): Promise<Array<T>>, static all<T>(promises: Array<?Promise<T> | T>): Promise<Array<T>>,
static race<T>(promises: Array<Promise<T>>): Promise<T>, static race<T>(promises: Array<Promise<T>>): Promise<T>,
static allObject<T: Object>(promisesByKey: T): Promise<{ static allObject<T: Object>(promisesByKey: T): Promise<{
[key: $Keys<T>]: any [key: $Keys<T>]: any
}> }>