diff --git a/src/printer.js b/src/printer.js index 9154b46c..e78ec971 100644 --- a/src/printer.js +++ b/src/printer.js @@ -600,13 +600,19 @@ function genericPrintNoParens(path, options, print) { fields.push("properties"); - var i = 0; var props = []; + let separatorParts = []; fields.forEach(function(field) { path.each( function(childPath) { + props.push(concat(separatorParts)); props.push(group(print(childPath))); + + separatorParts = [separator, line]; + if (util.isNextLineEmpty(options.originalText, childPath.getValue())) { + separatorParts.push(hardline); + } }, field ); @@ -639,7 +645,7 @@ function genericPrintNoParens(path, options, print) { options.tabWidth, concat([ options.bracketSpacing ? line : softline, - join(concat([separator, line]), props) + concat(props) ]) ), ifBreak(canHaveTrailingComma && options.trailingComma ? "," : ""), diff --git a/src/util.js b/src/util.js index 7b7c24e9..99c1585c 100644 --- a/src/util.js +++ b/src/util.js @@ -124,7 +124,7 @@ function skip(chars) { const skipWhitespace = skip(/\s/); const skipSpaces = skip(" \t"); -const skipToLineEnd = skip("; \t"); +const skipToLineEnd = skip(",; \t"); const skipEverythingButNewLine = skip(/[^\r\n]/); function skipInlineComment(text, index) { diff --git a/tests/flow/get-def/__snapshots__/jsfmt.spec.js.snap b/tests/flow/get-def/__snapshots__/jsfmt.spec.js.snap index 6f847d18..dff1ec58 100644 --- a/tests/flow/get-def/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/get-def/__snapshots__/jsfmt.spec.js.snap @@ -81,6 +81,7 @@ module.exports = { iTakeAString: function(name: string): number { return 42; }, + bar: function(): number { return 42; } diff --git a/tests/flow/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap b/tests/flow/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap index bdd2922b..b5830417 100644 --- a/tests/flow/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap @@ -210,29 +210,35 @@ var obj = { get goodGetterWithAnnotation(): number { return 4; }, + set goodSetterNoAnnotation(x) { z = x; }, set goodSetterWithAnnotation(x: number) { z = x; }, + get propWithMatchingGetterAndSetter(): number { return 4; }, set propWithMatchingGetterAndSetter(x: number) {}, + // The getter and setter need not have the same type get propWithSubtypingGetterAndSetter(): ?number { return 4; }, // OK set propWithSubtypingGetterAndSetter(x: number) {}, + set propWithSubtypingGetterAndSetterReordered(x: number) {}, // OK get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; }, + get exampleOfOrderOfGetterAndSetter(): A { return new A(); }, set exampleOfOrderOfGetterAndSetter(x: B) {}, + set exampleOfOrderOfGetterAndSetterReordered(x: B) {}, get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); diff --git a/tests/flow/missing_annotation/__snapshots__/jsfmt.spec.js.snap b/tests/flow/missing_annotation/__snapshots__/jsfmt.spec.js.snap index 2803fc17..5483c51d 100644 --- a/tests/flow/missing_annotation/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/missing_annotation/__snapshots__/jsfmt.spec.js.snap @@ -95,18 +95,21 @@ var Foo = { // missing arg annotation return arg; }, + b: function(arg) { // missing arg annotation return { bar: arg }; }, + c: function(arg: string) { // no return annotation required return { bar: arg }; }, + d: function( arg: string ): { @@ -116,6 +119,7 @@ var Foo = { bar: arg }; }, + // 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 // from annotations @@ -125,6 +129,7 @@ var Foo = { return x; }; }, + // ...if the return type is annotated explicitly, this is unnecessary f: function(arg: string): (x: number) => number { return function(x) { @@ -136,10 +141,13 @@ var Foo = { var Bar = { a: Foo.a(\"Foo\"), // no annotation required + // object property types are inferred, so make sure that this doesn\'t cause // us to also infer the parameter\'s type. b: Foo.b(\"bar\"), // no annotation required + c: Foo.c(\"bar\"), // no annotation required + d: Foo.d(\"bar\") // no annotation required }; diff --git a/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap b/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap index 3a2682fd..e567f9ae 100644 --- a/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/more_react/__snapshots__/jsfmt.spec.js.snap @@ -79,12 +79,15 @@ var App = React.createClass({ getDefaultProps: function(): { y: string } { return { y: \"\" }; // infer props.y: string }, + getInitialState: function() { return { z: 0 }; // infer state.z: number }, + handler: function() { this.setState({ z: 42 }); // ok }, + render: function() { var x = this.props.x; var y = this.props.y; diff --git a/tests/flow/new_react/__snapshots__/jsfmt.spec.js.snap b/tests/flow/new_react/__snapshots__/jsfmt.spec.js.snap index 44c78378..ceee6a56 100644 --- a/tests/flow/new_react/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/new_react/__snapshots__/jsfmt.spec.js.snap @@ -67,6 +67,7 @@ var FeedUFI = React.createClass({ ); }, + render: function(): ?React.Element { return
; } @@ -130,6 +131,7 @@ var UFILikeCount = React.createClass({ permalink: React.PropTypes.string, feedback: React.PropTypes.object.isRequired }, + render: function(): ?React.Element { return
; } @@ -337,22 +339,29 @@ var FooLegacy = React.createClass({ propTypes: { x: React.PropTypes.number.isRequired }, + getDefaultProps(): DefaultProps { return {}; }, + statics: { bar(): void {} }, + qux(): void { var _: string = this.props.x; }, + getInitialState(): { y: string } { return { y: \"\" }; }, + setState(o: { y_: string }): void {}, + componentDidMount(): void { this.is_mounted = true; }, + componentWillReceiveProps(nextProps: Object, nextContext: any): void { this.qux(); } @@ -452,6 +461,7 @@ var C = React.createClass({ z: React.PropTypes.number }, replaceProps(props: {}) {}, + getDefaultProps(): { z: number } { return { z: 0 }; }, @@ -558,9 +568,11 @@ var TestProps = React.createClass({ x: React.PropTypes.string, z: React.PropTypes.number }, + getDefaultProps: function() { return { x: \"\", y: 0 }; }, + test: function() { var a: number = this.props.x; // error var b: string = this.props.y; // error @@ -688,12 +700,14 @@ var TestProps = React.createClass({ object_rec: React.PropTypes.object.isRequired, string: React.PropTypes.string, string_rec: React.PropTypes.string.isRequired, + any: React.PropTypes.any, any_rec: React.PropTypes.any.isRequired, element: React.PropTypes.element, element_rec: React.PropTypes.element.isRequired, node: React.PropTypes.node, node_rec: React.PropTypes.node.isRequired, + arrayOf: React.PropTypes.arrayOf(React.PropTypes.string), arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, instanceOf: React.PropTypes.instanceOf(Object), @@ -718,6 +732,7 @@ var TestProps = React.createClass({ foo: React.PropTypes.string, bar: React.PropTypes.number }).isRequired, + // And do something bad here bad_one: React.PropTypes.imaginaryType, bad_two: React.PropTypes.string.inRequired @@ -840,6 +855,7 @@ var ReactClass = React.createClass({ getInitialState: function(): State { return { bar: null }; }, + render: function(): any { // Any state access here seems to make state any this.state; @@ -919,6 +935,7 @@ var TestState = React.createClass({ x: \"\" }; }, + test: function() { var a: number = this.state.x; // error @@ -951,6 +968,7 @@ var C = React.createClass({ getInitialState: function() { return { x: 0 }; }, + render() { this.setState({ y: 0 }); return
{this.state.z}
; diff --git a/tests/flow/overload/__snapshots__/jsfmt.spec.js.snap b/tests/flow/overload/__snapshots__/jsfmt.spec.js.snap index 45809dd3..6782e926 100644 --- a/tests/flow/overload/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/overload/__snapshots__/jsfmt.spec.js.snap @@ -65,6 +65,7 @@ var x4: number = \"\".split(/pattern/)[0]; declare class C { foo(x: number): number, foo(x: string): string, + bar(x: { a: number }): number, bar(x: { a: string }): string } diff --git a/tests/flow/react/__snapshots__/jsfmt.spec.js.snap b/tests/flow/react/__snapshots__/jsfmt.spec.js.snap index 9fbf4260..e3190c87 100644 --- a/tests/flow/react/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/react/__snapshots__/jsfmt.spec.js.snap @@ -271,6 +271,7 @@ var React = React.createClass({ return \"Alice\"; } }, + render() { // But this never errored return
; diff --git a/tests/flow/react_modules/__snapshots__/jsfmt.spec.js.snap b/tests/flow/react_modules/__snapshots__/jsfmt.spec.js.snap index ba395957..b92ca222 100644 --- a/tests/flow/react_modules/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/react_modules/__snapshots__/jsfmt.spec.js.snap @@ -34,6 +34,7 @@ var HelloLocal = React.createClass({ propTypes: { name: React.PropTypes.string.isRequired }, + render: function(): React.Element<*> { return
{this.props.name}
; } @@ -77,6 +78,7 @@ var Hello = React.createClass({ propTypes: { name: React.PropTypes.string.isRequired }, + render: function(): React.Element<*> { return
{this.props.name}
; } diff --git a/tests/flow/type-at-pos/__snapshots__/jsfmt.spec.js.snap b/tests/flow/type-at-pos/__snapshots__/jsfmt.spec.js.snap index 84dd79aa..67f64998 100644 --- a/tests/flow/type-at-pos/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/type-at-pos/__snapshots__/jsfmt.spec.js.snap @@ -33,6 +33,7 @@ export const X = { returnsATuple: function(): [number, number] { return [1, 2]; }, + test: function() { let [a, b] = this.returnsATuple(); } diff --git a/tests/flow/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap b/tests/flow/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap index b8d332ab..c373ecf9 100644 --- a/tests/flow/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap @@ -63,22 +63,29 @@ declare class Promise { reject: (error?: any) => void ) => void ): void, + then( onFulfill?: ?(value: R) => Promise | ?U, onReject?: ?(error: any) => Promise | ?U ): Promise, + done( onFulfill?: ?(value: R) => void, onReject?: ?(error: any) => void ): void, + catch(onReject?: (error: any) => ?Promise | U): Promise, + static resolve(object?: Promise | T): Promise, static reject(error?: any): Promise, + // Non-standard APIs finally(onSettled?: ?(value: any) => Promise | U): Promise, + static cast(object?: T): Promise, static all(promises: Array | T>): Promise>, static race(promises: Array>): Promise, + static allObject(promisesByKey: T): Promise<{ [key: $Keys]: any }>