diff --git a/src/comments.js b/src/comments.js index 5f49138a..6d043eb8 100644 --- a/src/comments.js +++ b/src/comments.js @@ -933,7 +933,10 @@ function printComment(commentPath, options) { return printJsDocComment(comment); } - return "/*" + comment.value + "*/"; + const isInsideFlowComment = + options.originalText.substr(util.locEnd(comment) - 3, 3) === "*-/"; + + return "/*" + comment.value + (isInsideFlowComment ? "*-/" : "*/"); } case "CommentLine": case "Line": diff --git a/src/printer.js b/src/printer.js index 79d6a557..5ef8e6b3 100644 --- a/src/printer.js +++ b/src/printer.js @@ -445,15 +445,10 @@ function genericPrintNoParens(path, options, print, args) { return concat(parts); case "Identifier": { - const parentNode = path.getParentNode(); - const isFunctionDeclarationIdentifier = - parentNode.type === "DeclareFunction" && parentNode.id === n; - return concat([ n.name, printOptionalToken(path), - n.typeAnnotation && !isFunctionDeclarationIdentifier ? ": " : "", - path.call(print, "typeAnnotation") + printTypeAnnotation(path, options, print) ]); } case "SpreadElement": @@ -468,8 +463,7 @@ function genericPrintNoParens(path, options, print, args) { return concat([ "...", path.call(print, "argument"), - n.typeAnnotation ? ": " : "", - path.call(print, "typeAnnotation") + printTypeAnnotation(path, options, print) ]); case "FunctionDeclaration": case "FunctionExpression": @@ -500,7 +494,7 @@ function genericPrintNoParens(path, options, print, args) { (args.expandLastArg || args.expandFirstArg), /* printTypeParams */ true ), - printReturnType(path, print) + printReturnType(path, print, options) ]) ) ); @@ -773,7 +767,7 @@ function genericPrintNoParens(path, options, print, args) { if ( !hasContent && !hasDirectives && - !n.comments && + !hasDanglingComments(n) && (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration" || @@ -1042,8 +1036,7 @@ function genericPrintNoParens(path, options, print, args) { ), concat([options.bracketSpacing ? line : softline, rightBrace]), printOptionalToken(path), - n.typeAnnotation ? ": " : "", - path.call(print, "typeAnnotation") + printTypeAnnotation(path, options, print) ]); } @@ -1173,11 +1166,10 @@ function genericPrintNoParens(path, options, print, args) { ); } - parts.push(printOptionalToken(path)); - - if (n.typeAnnotation) { - parts.push(": ", path.call(print, "typeAnnotation")); - } + parts.push( + printOptionalToken(path), + printTypeAnnotation(path, options, print) + ); return concat(parts); case "SequenceExpression": { @@ -1940,9 +1932,7 @@ function genericPrintNoParens(path, options, print, args) { } else { parts.push(printPropertyKey(path, options, print)); } - if (n.typeAnnotation) { - parts.push(": ", path.call(print, "typeAnnotation")); - } + parts.push(printTypeAnnotation(path, options, print)); if (n.value) { parts.push( " =", @@ -3010,7 +3000,7 @@ function printMethod(path, options, print) { group( concat([ printFunctionParams(valuePath, print, options), - printReturnType(valuePath, print) + printReturnType(valuePath, print, options) ]) ) ], @@ -3204,6 +3194,26 @@ function printArgumentsList(path, options, print) { ); } +function printTypeAnnotation(path, options, print) { + const node = path.getValue(); + if (!node.typeAnnotation) { + return ""; + } + + const parentNode = path.getParentNode(); + const isFunctionDeclarationIdentifier = + parentNode.type === "DeclareFunction" && parentNode.id === node; + + if (isFlowAnnotationComment(options.originalText, node.typeAnnotation)) { + return concat([" /*: ", path.call(print, "typeAnnotation"), " */"]); + } + + return concat([ + isFunctionDeclarationIdentifier ? "" : ": ", + path.call(print, "typeAnnotation") + ]); +} + function printFunctionTypeParameters(path, options, print) { const fun = path.getValue(); if (fun.typeParameters) { @@ -3396,7 +3406,7 @@ function printFunctionDeclaration(path, print, options) { group( concat([ printFunctionParams(path, print, options), - printReturnType(path, print) + printReturnType(path, print, options) ]) ), n.body ? " " : "", @@ -3437,7 +3447,7 @@ function printObjectMethod(path, options, print) { group( concat([ printFunctionParams(path, print, options), - printReturnType(path, print) + printReturnType(path, print, options) ]) ), " ", @@ -3447,9 +3457,18 @@ function printObjectMethod(path, options, print) { return concat(parts); } -function printReturnType(path, print) { +function printReturnType(path, print, options) { const n = path.getValue(); - const parts = [path.call(print, "returnType")]; + const returnType = path.call(print, "returnType"); + + if ( + n.returnType && + isFlowAnnotationComment(options.originalText, n.returnType) + ) { + return concat([" /*: ", returnType, " */"]); + } + + const parts = [returnType]; // prepend colon to TypeScript type annotation if (n.returnType && n.returnType.typeAnnotation) { @@ -4770,6 +4789,12 @@ function hasNakedLeftSide(node) { ); } +function isFlowAnnotationComment(text, typeAnnotation) { + const start = util.locStart(typeAnnotation); + const end = util.skipWhitespace(text, util.locEnd(typeAnnotation)); + return text.substr(start, 2) === "/*" && text.substr(end, 2) === "*/"; +} + function getLeftSide(node) { if (node.expressions) { return node.expressions[0]; diff --git a/tests/comments/__snapshots__/jsfmt.spec.js.snap b/tests/comments/__snapshots__/jsfmt.spec.js.snap index ba1df1f9..cc30ecca 100644 --- a/tests/comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/comments/__snapshots__/jsfmt.spec.js.snap @@ -339,31 +339,24 @@ KEYPAD_NUMBERS.map(( function f /* f */() {} function f(/* args */) {} -function f() /* returns */ { -} -function f /* f */(/* args */) /* returns */ { -} +function f() /* returns */ {} +function f /* f */(/* args */) /* returns */ {} function f /* f */(/* a */ a) {} function f /* f */(a /* a */) {} -function f /* f */(/* a */ a) /* returns */ { -} +function f /* f */(/* a */ a) /* returns */ {} const obj = { f1 /* f */() {}, f2(/* args */) {}, - f3() /* returns */ { - }, - f4 /* f */(/* args */) /* returns */ { - } + f3() /* returns */ {}, + f4 /* f */(/* args */) /* returns */ {} }; (function f /* f */() {})(); (function f(/* args */) {})(); -(function f() /* returns */ { -})(); -(function f /* f */(/* args */) /* returns */ { -})(); +(function f() /* returns */ {})(); +(function f /* f */(/* args */) /* returns */ {})(); class C { f /* f */() {} @@ -372,12 +365,10 @@ class C { f(/* args */) {} } class C { - f() /* returns */ { - } + f() /* returns */ {} } class C { - f /* f */(/* args */) /* returns */ { - } + f /* f */(/* args */) /* returns */ {} } `; @@ -1133,8 +1124,7 @@ class Foo { lol2 /*string*/, lol3 /*string*/, lol4 /*string*/ - ) /*string*/ { - } + ) /*string*/ {} // prettier-ignore c(lol /*string*/ diff --git a/tests/empty_paren_comment/__snapshots__/jsfmt.spec.js.snap b/tests/empty_paren_comment/__snapshots__/jsfmt.spec.js.snap index f5ec778a..9992ec4c 100644 --- a/tests/empty_paren_comment/__snapshots__/jsfmt.spec.js.snap +++ b/tests/empty_paren_comment/__snapshots__/jsfmt.spec.js.snap @@ -61,8 +61,7 @@ const obj = { class Foo { f(/* ... */) {} - f() /* ... */ { - } + f() /* ... */ {} f = (/* ... */) => {}; static f(/* ... */) {} static f = (/* ... */) => {}; diff --git a/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap b/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap index 4176aa20..56c178ce 100644 --- a/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap @@ -38,7 +38,7 @@ type Children = Array; class Thunk {} class VirtualNode { children: Child | Children; - constructor(type, children: Children) { + constructor(type, children /*: Children */) { this.children = children.length === 1 ? children[0] : children; } } diff --git a/tests/flow_comments/__snapshots__/jsfmt.spec.js.snap b/tests/flow_comments/__snapshots__/jsfmt.spec.js.snap index ffde0178..9bcc289f 100644 --- a/tests/flow_comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow_comments/__snapshots__/jsfmt.spec.js.snap @@ -2,39 +2,55 @@ exports[`arrow.js 1`] = ` // Error -const beep = (data/*: Object*/) => {} +const beep = (data/*: Object */) => {} // OK -const beep = (data/*: Object*/, secondData/*: Object*/) => {} +const beep = (data/*: Object */, secondData/*: Object */) => {} + +const beep = (data/*: /* this is an object *-/ Object */) => {}; const run = (cmd /*: string */) /*: Promise */ => {} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Error -const beep = (data: Object) => {}; +const beep = (data /*: Object */) => {}; // OK -const beep = (data: Object, secondData: Object) => {}; +const beep = (data /*: Object */, secondData /*: Object */) => {}; -const run = (cmd: string): Promise => {}; +const beep = (data /*: /* this is an object *-/ Object */) => {}; + +const run = (cmd /*: string */) /*: Promise */ => {}; `; -exports[`arrow.js 2`] = ` -// Error -const beep = (data/*: Object*/) => {} +exports[`class.js 1`] = ` +class A { + x /*: string */; -// OK -const beep = (data/*: Object*/, secondData/*: Object*/) => {} - -const run = (cmd /*: string */) /*: Promise */ => {} + method(a /*: T */, b /*: T */) /*: T */ {} +} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Error -const beep = (data /*: Object*/) => {}; +class A { + x /*: string */; -// OK -const beep = (data /*: Object*/, secondData /*: Object*/) => {}; + method(a /*: T */, b /*: T */) /*: T */ {} +} -const run = (cmd /*: string */) /*: Promise */ => {}; +`; + +exports[`functions.js 1`] = ` +function foo(bar /*: T[] */, baz /*: T */) /*: S */ {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(bar /*: T[] */, baz /*: T */) /*: S */ {} + +`; + +exports[`let.js 1`] = ` +let foo /*: Groups */; +let foo /*: string */ = 'a'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +let foo /*: Groups */; +let foo /*: string */ = "a"; `; @@ -69,35 +85,3 @@ type Props = { }; `; - -exports[`object_type_annotation.js 2`] = ` -type Props = // (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! -{ - isPlaying: boolean, -}; - -type Props = { // (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! - isPlaying: boolean -}; - -type Props = { - // (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! - isPlaying: boolean -}; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! -type Props = { - isPlaying: boolean -}; - -type Props = { - // (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! - isPlaying: boolean -}; - -type Props = { - // (DispatchProps & StateProps); WHY DON'T YOU WORK FLOW!!!!!!!!! - isPlaying: boolean -}; - -`; diff --git a/tests/flow_comments/arrow.js b/tests/flow_comments/arrow.js index 869078c1..4641734a 100644 --- a/tests/flow_comments/arrow.js +++ b/tests/flow_comments/arrow.js @@ -1,7 +1,9 @@ // Error -const beep = (data/*: Object*/) => {} +const beep = (data/*: Object */) => {} // OK -const beep = (data/*: Object*/, secondData/*: Object*/) => {} +const beep = (data/*: Object */, secondData/*: Object */) => {} + +const beep = (data/*: /* this is an object *-/ Object */) => {}; const run = (cmd /*: string */) /*: Promise */ => {} diff --git a/tests/flow_comments/class.js b/tests/flow_comments/class.js new file mode 100644 index 00000000..961e66f6 --- /dev/null +++ b/tests/flow_comments/class.js @@ -0,0 +1,5 @@ +class A { + x /*: string */; + + method(a /*: T */, b /*: T */) /*: T */ {} +} diff --git a/tests/flow_comments/functions.js b/tests/flow_comments/functions.js new file mode 100644 index 00000000..3d53f13c --- /dev/null +++ b/tests/flow_comments/functions.js @@ -0,0 +1 @@ +function foo(bar /*: T[] */, baz /*: T */) /*: S */ {} diff --git a/tests/flow_comments/jsfmt.spec.js b/tests/flow_comments/jsfmt.spec.js index f1cc326d..c1ba82f4 100644 --- a/tests/flow_comments/jsfmt.spec.js +++ b/tests/flow_comments/jsfmt.spec.js @@ -1,3 +1 @@ -run_spec(__dirname, ["flow"]); -// FIXME arrow.js flow != babylon output -run_spec(__dirname, ["babylon"]); +run_spec(__dirname, ["flow", "babylon"]); diff --git a/tests/flow_comments/let.js b/tests/flow_comments/let.js new file mode 100644 index 00000000..8fa12e7c --- /dev/null +++ b/tests/flow_comments/let.js @@ -0,0 +1,2 @@ +let foo /*: Groups */; +let foo /*: string */ = 'a';