From 7ea2348b03c7eec0ab541dc8fa2d8d477a6a1627 Mon Sep 17 00:00:00 2001 From: James Long Date: Fri, 30 Dec 2016 17:00:11 -0500 Subject: [PATCH] Various fixes with destructuring default, JSX, and more; all tests pass! --- package.json | 3 +- src/fast-path.js | 10 +- src/printer.js | 47 +++-- .../__snapshots__/jsfmt.spec.js.snap | 6 +- .../__snapshots__/jsfmt.spec.js.snap | 18 +- .../__snapshots__/jsfmt.spec.js.snap | 4 +- .../get-def2/__snapshots__/jsfmt.spec.js.snap | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 160 ------------------ 9 files changed, 58 insertions(+), 194 deletions(-) delete mode 100644 tests/more_react/__snapshots__/jsfmt.spec.js.snap diff --git a/package.json b/package.json index ffedfd89..46c1061d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "jsfmt\\.spec\\.js$" ], "testPathIgnorePatterns": [ - "tests/new_react" + "tests/new_react", + "tests/more_react" ] } } diff --git a/src/fast-path.js b/src/fast-path.js index 8845d6ac..9ec8f060 100644 --- a/src/fast-path.js +++ b/src/fast-path.js @@ -320,7 +320,8 @@ FPp.needsParens = function(assumeExpressionContext) { return parent.type === "ArrayTypeAnnotation"; case "FunctionTypeAnnotation": - return parent.type === "UnionTypeAnnotation"; + return parent.type === "UnionTypeAnnotation" || + parent.type === "IntersectionTypeAnnotation"; case "Literal": return parent.type === "MemberExpression" @@ -351,7 +352,8 @@ FPp.needsParens = function(assumeExpressionContext) { && parent.object === node; default: - return false; + return n.ObjectPattern.check(node.left) && + this.firstInStatement(); } case "ArrowFunctionExpression": @@ -439,7 +441,9 @@ FPp.canBeFirstInStatement = function() { var node = this.getNode(); return !n.FunctionExpression.check(node) && !n.ObjectExpression.check(node) - && !n.ClassExpression.check(node); + && !n.ClassExpression.check(node) + && !(n.AssignmentExpression.check(node) && + n.ObjectPattern.check(node.left)); }; FPp.firstInStatement = function() { diff --git a/src/printer.js b/src/printer.js index 41cc6200..d127fdba 100644 --- a/src/printer.js +++ b/src/printer.js @@ -165,7 +165,7 @@ function genericPrint(path, options, printPath) { var linesWithoutParens = genericPrintNoParens(path, options, printPath); - if (! node || isEmpty(linesWithoutParens)) { + if (!node || isEmpty(linesWithoutParens)) { return linesWithoutParens; } @@ -668,15 +668,18 @@ function genericPrintNoParens(path, options, print) { return printMethod(path, options, print); } - var key = path.call(print, "key"); if (n.computed) { - parts.push("[", key, "]"); - } else { - parts.push(key); + parts.push("[", path.call(print, "key"), "]") + } + else { + parts.push(path.call(print, n.shorthand ? "value" : "key")); } - if (! n.shorthand) { - parts.push(": ", path.call(print, "value")); + if(!n.shorthand) { + parts.push( + ": ", + path.call(print, "value") + ); } return concat(parts); @@ -1082,19 +1085,27 @@ function genericPrintNoParens(path, options, print) { return openingLines; } - var children = path.map(function(childPath) { + var children = []; + path.map(function(childPath) { var child = childPath.getValue(); if (namedTypes.Literal.check(child) && typeof child.value === "string") { if (/\S/.test(child.value)) { - return child.value.replace(/^\s+|\s+$/g, "").replace(/\n/, hardline); + const beginBreak = child.value.match(/^\s*\n/); + const endBreak = child.value.match(/\n\s*$/); + children.push( + beginBreak ? hardline : "", + child.value.replace(/^\s+|\s+$/g, ""), + endBreak ? hardline : "" + ); } else if (/\n/.test(child.value)) { - return hardline; + children.push(hardline); } } - - return print(childPath); + else { + children.push(print(childPath)); + } }, "children"); var mostChildren = children.slice(0, -1); @@ -1120,10 +1131,10 @@ function genericPrintNoParens(path, options, print) { return concat([""]); case "JSXText": - return fromString(n.value, options); + throw new Error("JSXTest should be handled by JSXElement"); case "JSXEmptyExpression": - return fromString(""); + return ""; case "TypeAnnotatedIdentifier": return concat([ @@ -1425,7 +1436,11 @@ function genericPrintNoParens(path, options, print) { return fromString("number", options); case "ObjectTypeCallProperty": - return path.call(print, "value"); + if(n.static) { + parts.push("static "); + } + parts.push(path.call(print, "value")); + return concat(parts); case "ObjectTypeIndexer": var variance = @@ -1808,12 +1823,12 @@ function printExportDeclaration(path, options, print) { } else if (decl.specifiers && decl.specifiers.length > 0) { - if (decl.specifiers.length === 1 && decl.specifiers[0].type === "ExportBatchSpecifier") { parts.push("*"); } else { parts.push( + decl.exportKind === "type" ? "type " : "", shouldPrintSpaces ? "{ " : "{", join(", ", path.map(print, "specifiers")), shouldPrintSpaces ? " }" : "}" diff --git a/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap b/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap index fb2dfccb..8b20712f 100644 --- a/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap +++ b/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap @@ -40,7 +40,11 @@ Foo.prototype = { }; exports.Foo = Foo; interface IFooPrototype { m(): number } -interface IFoo extends IFooPrototype { (): void; x: boolean; static y: boolean } +interface IFoo extends IFooPrototype { + static (): void; + x: boolean; + static y: boolean +} exports.Foo2 = (Foo: Class); " `; diff --git a/tests/destructuring/__snapshots__/jsfmt.spec.js.snap b/tests/destructuring/__snapshots__/jsfmt.spec.js.snap index 41066e67..dcba7329 100644 --- a/tests/destructuring/__snapshots__/jsfmt.spec.js.snap +++ b/tests/destructuring/__snapshots__/jsfmt.spec.js.snap @@ -180,7 +180,7 @@ function default_expr_scope({a, b = a}) {} // ok // union-like upper bounds preserved through destructuring // TODO: union-of-objects upper bounds preserved through destructuring -function obj_prop_fun({ p: { q } = { q: true } } = { p: { q: \"\" } }) { +function obj_prop_fun({ p: { q = 0 } = { q: true } } = { p: { q: \"\" } }) { (q: void); } obj_prop_fun(); @@ -188,7 +188,7 @@ obj_prop_fun({}); obj_prop_fun({ p: {} }); obj_prop_fun({ p: { q: null } }); function obj_prop_var(o = { p: { q: \"\" } }) { - var { p: { q } = { q: true } } = o; + var { p: { q = 0 } = { q: true } } = o; (q: void); } obj_prop_var(); @@ -204,10 +204,10 @@ obj_rest(); obj_rest({}); obj_rest({ p: {} }); obj_rest({ p: { q: 0, r: null } }); -function obj_prop_annot({ p }: { p: string } = { p: 0 }) { +function obj_prop_annot({ p = true }: { p: string } = { p: 0 }) { (p: void); } -var { p }: { p: string } = { p: 0 }; +var { p = true }: { p: string } = { p: 0 }; (p: void); function obj_prop_err({ x: { y } } = null) { @@ -221,7 +221,7 @@ function arr_elem_err([ x ] = null) { function arr_rest_err([ ...a ] = null) { } -function gen(x: T, { p }: { p: T }): T { +function gen(x: T, { p = x }: { p: T }): T { return p; } obj_prop_fun(({}: { p?: { q?: null } })); @@ -238,7 +238,7 @@ function obj_prop_union({ p }: { p: number | string } = { p: true }) { function obj_prop_union2({ p }: { p: number } | { p: string } = { p: true }) { } -function default_expr_scope({ a, b }) { +function default_expr_scope({ a, b = a }) { } " @@ -330,9 +330,9 @@ declare var b: string; declare var c: string; [ { a1: a, b }, c ] = [ { a1: 0, b: 1 }, 2 ]; var { m } = { m: 0 }; -{ m } = { m: m }; +({ m } = { m: m }); var obj; -{ n: obj.x } = { n: 3 }; +({ n: obj.x } = { n: 3 }); [ obj.x ] = [ \"foo\" ]; function foo({ p, z: [ r ] }) { a = p; @@ -420,7 +420,7 @@ exports[`test eager.js 1`] = ` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // error, property \`x\` can not be accessed on \`null\` var x; -{ x } = null; +({ x } = null); " `; diff --git a/tests/export_type/__snapshots__/jsfmt.spec.js.snap b/tests/export_type/__snapshots__/jsfmt.spec.js.snap index 9e441236..3b639fa9 100644 --- a/tests/export_type/__snapshots__/jsfmt.spec.js.snap +++ b/tests/export_type/__snapshots__/jsfmt.spec.js.snap @@ -99,10 +99,10 @@ export type inlinedType1 = number; var a: inlinedType1 = 42; var b: inlinedType1 = \"asdf\"; type standaloneType1 = number; -export { standaloneType1 } +export type { standaloneType1 } type standaloneType2 = number; export { standaloneType2 } -export { talias1, talias2 as talias3, IFoo2 } from \"./types_only2\" +export type { talias1, talias2 as talias3, IFoo2 } from \"./types_only2\" export interface IFoo { prop: number } " `; diff --git a/tests/get-def2/__snapshots__/jsfmt.spec.js.snap b/tests/get-def2/__snapshots__/jsfmt.spec.js.snap index 55805842..a8b69d5e 100644 --- a/tests/get-def2/__snapshots__/jsfmt.spec.js.snap +++ b/tests/get-def2/__snapshots__/jsfmt.spec.js.snap @@ -45,7 +45,7 @@ import type {Foo} from \'./types\'; // Follows non-destructured property access of \`require(\'Parent\')\` var Parent = require(\"./Parent\"); let ParentFoo; -{ ParentFoo } = Parent; +({ ParentFoo } = Parent); ParentFoo; let ParentFoo2; ParentFoo2 = Parent; diff --git a/tests/intersection/__snapshots__/jsfmt.spec.js.snap b/tests/intersection/__snapshots__/jsfmt.spec.js.snap index 917a0deb..35f46c7e 100644 --- a/tests/intersection/__snapshots__/jsfmt.spec.js.snap +++ b/tests/intersection/__snapshots__/jsfmt.spec.js.snap @@ -147,7 +147,7 @@ type FG = (_: ObjA | ObjB) => void; declare var fun1: F & G; (fun1: FG); var fun2: FG = fun1; -declare var f: (_: number) => void & (_: string) => void; +declare var f: ((_: number) => void) & ((_: string) => void); var g: (_: number | string) => void = f; " `; diff --git a/tests/more_react/__snapshots__/jsfmt.spec.js.snap b/tests/more_react/__snapshots__/jsfmt.spec.js.snap deleted file mode 100644 index 7f531901..00000000 --- a/tests/more_react/__snapshots__/jsfmt.spec.js.snap +++ /dev/null @@ -1,160 +0,0 @@ -exports[`test API.react.js 1`] = ` -" -var app = require(\'JSX\'); - -app.setProps({y:42}); // error, y:number but foo expects string in App.react -app.setState({z:42}); // error, z:number but foo expects string in App.react - -function bar(x:number) { } -bar(app.props.children); // No error, App doesn\'t specify propTypes so anything goes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// error, y:number but foo expects string in App.react -// error, z:number but foo expects string in App.react -// No error, App doesn\'t specify propTypes so anything goes -var app = require(\"JSX\"); -app.setProps({ y: 42 }); -app.setState({ z: 42 }); -function bar(x: number) { - -} -bar(app.props.children); -" -`; - -exports[`test App.react.js 1`] = ` -" -/** - * @providesModule App.react - * @jsx React.DOM - */ - -var React = require(\'react\'); - -// expect args to be strings -function foo(p:string,q:string):string { return p+q; } - -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; - var z = this.state.z; - - //this.state; - - return ( -
- {foo(x,y)} - {foo(z,x)} // error, since z: number -
- ); - } - -}); - -module.exports = App; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/** - * @providesModule App.react - * @jsx React.DOM - */ -// expect args to be strings -// infer props.y: string -// infer state.z: number -// ok -//this.state; -var React = require(\"react\"); -function foo(p: string, q: string): string { - return p + q; -} -var App = React.createClass({ - getDefaultProps: function(): { y: string } { - return { y: \"\" }; - }, - getInitialState: function() { - return { z: 0 }; - }, - handler: function() { - this.setState({ z: 42 }); - }, - render: function() { - var x = this.props.x; - var y = this.props.y; - var z = this.state.z; - return ( -
- {foo(x, y)} - {foo(z, x)}// error, since z: number
- ); - } -}); -module.exports = App; -" -`; - -exports[`test JSX.js 1`] = ` -" -/* @providesModule JSX */ - -var React = require(\'react\'); -var App = require(\'App.react\'); - -var app = - // error, y: number but foo expects string in App.react - Some text. - ; - -module.exports = app; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* @providesModule JSX */ -var React = require(\"react\"); -var App = require(\"App.react\"); -var app = // error, y: number but foo expects string in App.react[object Object] Some text.; -module.exports = app; -" -`; - -exports[`test propTypes.js 1`] = ` -"var React = require(\'React\'); - -var C = React.createClass({ - propTypes: { - title: React.PropTypes.string.isRequired, - } -}); -var D = React.createClass({ - propTypes: { - name: React.PropTypes.string.isRequired, - ...C.propTypes, - } -}); - -; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* error (as usual)*/ -/* OK (error ignored when spread is used)*/ -var React = require(\"React\"); -var C = React.createClass({ - propTypes: { title: React.PropTypes.string.isRequired } -}); -var D = React.createClass({ - propTypes: { name: React.PropTypes.string.isRequired, ...C.propTypes } -}); -; -" -`;