diff --git a/README.md b/README.md index 937fdcdc9..be0784540 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,17 @@ you can pass `--no-config` instead. Path to a file containing patterns that describe files to ignore. By default, prettier looks for `./.prettierignore`. +#### `--require-pragma` + +Require a special comment, called a pragma, to be present in the file's first docblock comment in order for prettier to format it. +```js +/** + * @prettier + */ +``` + +Valid pragmas are `@prettier` and `@format`. + #### `--list-different` Another useful flag is `--list-different` (or `-l`) which prints the filenames of files that are different from Prettier formatting. If there are differences the script errors out, which is useful in a CI scenario. @@ -288,7 +299,7 @@ Do not look for a configuration file. The default settings will be used. #### `--config-precedence` -Defines how config file should be evaluated in combination of CLI options. +Defines how config file should be evaluated in combination of CLI options. **cli-override (default)** @@ -659,6 +670,30 @@ Default | CLI Override | API Override --------|--------------|------------- None | `--stdin-filepath ` | `filepath: ""` +### Require pragma +Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file. This is very useful +when gradually transitioning large, unformatted codebases to prettier. + +For example, a file with the following as its first comment will be formatted when `--require-pragma` is supplied: + +```js +/** + * @prettier + */ +``` + +or + +```js +/** + * @format + */ +``` + +Default | CLI Override | API Override +--------|--------------|------------- +`false` | `--require-pragma` | `requirePragma` + ## Configuration File Prettier uses [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) for configuration file support. diff --git a/docs/options.md b/docs/options.md index 06406013d..5c9868be2 100644 --- a/docs/options.md +++ b/docs/options.md @@ -133,3 +133,26 @@ Default | CLI Override | API Override --------|--------------|------------- None | `--stdin-filepath ` | `filepath: ""` +## Require pragma +Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file. This is very useful +when gradually transitioning large, unformatted codebases to prettier. + +For example, a file with the following as its first comment will be formatted when `--require-pragma` is supplied: + +```js +/** + * @prettier + */ +``` + +or + +```js +/** + * @format + */ +``` + +Default | CLI Override | API Override +--------|--------------|------------- +`false` | `--require-pragma` | `requirePragma` diff --git a/editors/webstorm/README.md b/editors/webstorm/README.md index c6c032b9a..b32288b28 100644 --- a/editors/webstorm/README.md +++ b/editors/webstorm/README.md @@ -6,7 +6,7 @@ Go to *File | Settings | Tools | External Tools* for Windows and Linux or *WebSt * **Program** set `prettier` -> If on the other hand you have `prettier` installed locally, replace the **Program** with `./node_modules/.bin/prettier` (on OS X and Linux) or `.\node_modules\.bin\prettier.cmd` (on Windows). +> If on the other hand you have `prettier` installed locally, replace the **Program** with `$ProjectFileDir$/node_modules/.bin/prettier` (on OS X and Linux) or `$ProjectFileDir$\node_modules\.bin\prettier.cmd` (on Windows). * **Parameters** set `--write [other opts] $FilePathRelativeToProjectRoot$` * **Working directory** set `$ProjectFileDir$` @@ -16,7 +16,7 @@ Go to *File | Settings | Tools | External Tools* for Windows and Linux or *WebSt ### Process directories * Clone the External tool created above and name it `Prettier Directories` -* **Parameters** set `--write [other opts] $FileDirRelativeToProjectRoot$/**/(*.js|*.jsx)` +* **Parameters** set `--write [other opts] $FileDirRelativeToProjectRoot$/**/{*.js,*.jsx}` ## Usage diff --git a/index.js b/index.js index cb351acc6..25452ce78 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,7 @@ const normalizeOptions = require("./src/options").normalize; const parser = require("./src/parser"); const printDocToDebug = require("./src/doc-debug").printDocToDebug; const config = require("./src/resolve-config"); +const docblock = require("jest-docblock"); function guessLineEnding(text) { const index = text.indexOf("\n"); @@ -30,6 +31,11 @@ function attachComments(text, ast, opts) { return astComments; } +function hasPragma(text) { + const pragmas = Object.keys(docblock.parse(docblock.extract(text))); + return pragmas.indexOf("prettier") !== -1 || pragmas.indexOf("format") !== -1; +} + function ensureAllCommentsPrinted(astComments) { if (!astComments) { return; @@ -56,6 +62,10 @@ function ensureAllCommentsPrinted(astComments) { } function formatWithCursor(text, opts, addAlignmentSize) { + if (opts.requirePragma && !hasPragma(text)) { + return { formatted: text }; + } + text = stripBom(text); addAlignmentSize = addAlignmentSize || 0; diff --git a/package.json b/package.json index 305b4f870..49db81f52 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "globby": "^6.1.0", "graphql": "0.10.1", "ignore": "^3.3.3", + "jest-docblock": "^21.0.2", "jest-validate": "20.0.3", "minimatch": "3.0.4", "minimist": "1.2.0", diff --git a/scripts/build/build.js b/scripts/build/build.js index a0fc77ced..106f3921a 100755 --- a/scripts/build/build.js +++ b/scripts/build/build.js @@ -98,6 +98,14 @@ shell.sed( "dist/bin/prettier.js" ); +shell.echo("Update ISSUE_TEMPLATE.md"); +shell.sed( + "-i", + /(Prettier Version.+?)\d+\.\d+\.\d+/, + `$1${pkg.version}`, + ".github/ISSUE_TEMPLATE.md" +); + shell.echo("Create prettier-version.js"); pipe(`prettierVersion = "${pkg.version}";\n`).to(`${docs}/prettier-version.js`); diff --git a/src/clean-ast.js b/src/clean-ast.js index 921f1dfd3..489c76969 100644 --- a/src/clean-ast.js +++ b/src/clean-ast.js @@ -4,9 +4,9 @@ function cleanAST(ast) { return JSON.stringify(massageAST(ast), null, 2); } -function massageAST(ast) { +function massageAST(ast, parent) { if (Array.isArray(ast)) { - return ast.map(e => massageAST(e)).filter(e => e); + return ast.map(e => massageAST(e, parent)).filter(e => e); } if (ast && typeof ast === "object") { // We remove extra `;` and add them when needed @@ -29,7 +29,7 @@ function massageAST(ast) { const newObj = {}; for (const key in ast) { if (typeof ast[key] !== "function") { - newObj[key] = massageAST(ast[key]); + newObj[key] = massageAST(ast[key], ast); } } @@ -219,6 +219,7 @@ function massageAST(ast) { quasis.forEach(q => delete q.value); } + // styled-components and graphql if ( ast.type === "TaggedTemplateExpression" && @@ -231,6 +232,13 @@ function massageAST(ast) { ) { newObj.quasi.quasis.forEach(quasi => delete quasi.value); } + if ( + ast.type === "TemplateLiteral" && + parent.type === "CallExpression" && + parent.callee.name === "graphql" + ) { + newObj.quasis.forEach(quasi => delete quasi.value); + } return newObj; } diff --git a/src/cli-constant.js b/src/cli-constant.js index 5b0a7bb36..7068dc002 100644 --- a/src/cli-constant.js +++ b/src/cli-constant.js @@ -200,6 +200,14 @@ const detailedOptions = normalizeDetailedOptions({ Defaults to 0. `) }, + "require-pragma": { + type: "boolean", + forwardToApi: true, + description: dedent(` + Require either '@prettier' or '@format' to be present in the file's first docblock comment + in order for it to be formatted. + `) + }, semi: { type: "boolean", category: CATEGORY_FORMAT, diff --git a/src/cli-util.js b/src/cli-util.js index b62c6cbb5..aeb3504c9 100644 --- a/src/cli-util.js +++ b/src/cli-util.js @@ -226,7 +226,14 @@ function eachFilename(argv, patterns, callback) { } try { - const filePaths = globby.sync(patterns, { dot: true }); + const filePaths = globby + .sync(patterns, { dot: true }) + .map( + filePath => + path.isAbsolute(filePath) + ? path.relative(process.cwd(), filePath) + : filePath + ); if (filePaths.length === 0) { console.error(`No matching files. Patterns tried: ${patterns.join(" ")}`); process.exitCode = 2; diff --git a/src/comments.js b/src/comments.js index 1307bf12d..b5e0675f7 100644 --- a/src/comments.js +++ b/src/comments.js @@ -466,12 +466,12 @@ function handleIfStatementComments( } // We unfortunately have no way using the AST or location of nodes to know - // if the comment is positioned before or after the condition parenthesis: + // if the comment is positioned before the condition parenthesis: // if (a /* comment */) {} - // if (a) /* comment */ {} // The only workaround I found is to look at the next character to see if // it is a ). - if (getNextNonSpaceNonCommentCharacter(text, comment) === ")") { + const nextCharacter = getNextNonSpaceNonCommentCharacter(text, comment); + if (nextCharacter === ")") { addTrailingComment(precedingNode, comment); return true; } @@ -486,6 +486,16 @@ function handleIfStatementComments( return true; } + // For comments positioned after the condition parenthesis in an if statement + // before the consequent with or without brackets on, such as + // if (a) /* comment */ {} or if (a) /* comment */ true, + // we look at the next character to see if it is a { or if the following node + // is the consequent for the if statement + if (nextCharacter === "{" || enclosingNode.consequent === followingNode) { + addLeadingComment(followingNode, comment); + return true; + } + return false; } diff --git a/src/multiparser.js b/src/multiparser.js index 8f0f7b024..574b5fa70 100644 --- a/src/multiparser.js +++ b/src/multiparser.js @@ -68,14 +68,17 @@ function fromBabylonFlowOrTypeScript(path) { */ if ( parentParent && - parentParent.type === "TaggedTemplateExpression" && - parent.quasis.length === 1 && - ((parentParent.tag.type === "MemberExpression" && - parentParent.tag.object.name === "graphql" && - parentParent.tag.property.name === "experimental") || - (parentParent.tag.type === "Identifier" && - (parentParent.tag.name === "gql" || - parentParent.tag.name === "graphql"))) + ((parentParent.type === "TaggedTemplateExpression" && + parent.quasis.length === 1 && + ((parentParent.tag.type === "MemberExpression" && + parentParent.tag.object.name === "graphql" && + parentParent.tag.property.name === "experimental") || + (parentParent.tag.type === "Identifier" && + (parentParent.tag.name === "gql" || + parentParent.tag.name === "graphql")))) || + (parentParent.type === "CallExpression" && + parentParent.callee.type === "Identifier" && + parentParent.callee.name === "graphql")) ) { return { options: { parser: "graphql" }, diff --git a/src/options.js b/src/options.js index 0a9877d23..7bfaa140e 100644 --- a/src/options.js +++ b/src/options.js @@ -15,6 +15,7 @@ const defaults = { bracketSpacing: true, jsxBracketSameLine: false, parser: "babylon", + requirePragma: false, semi: true }; diff --git a/src/printer.js b/src/printer.js index 977da24c4..0ab076f88 100644 --- a/src/printer.js +++ b/src/printer.js @@ -338,32 +338,51 @@ function genericPrintNoParens(path, options, print, args) { ); } - // Avoid indenting sub-expressions in assignment/return/etc statements. - if ( - parent.type === "AssignmentExpression" || - parent.type === "VariableDeclarator" || - shouldInlineLogicalExpression(n) || + // Avoid indenting sub-expressions in some cases where the first sub-expression is already + // idented accordingly. We should ident sub-expressions where the first case isn't idented. + const shouldNotIdent = parent.type === "ReturnStatement" || (parent.type === "JSXExpressionContainer" && parentParent.type === "JSXAttribute") || (n === parent.body && parent.type === "ArrowFunctionExpression") || (n !== parent.body && parent.type === "ForStatement") || + (parent.type === "ConditionalExpression" && + parentParent.type !== "ReturnStatement"); + + const shouldIdentIfInlining = + parent.type === "AssignmentExpression" || + parent.type === "VariableDeclarator" || parent.type === "ObjectProperty" || - parent.type === "Property" || - parent.type === "ConditionalExpression" + parent.type === "Property"; + + const logicalSubExpression = n.left.type === "LogicalExpression"; + + if ( + shouldNotIdent || + (shouldInlineLogicalExpression(n) && !logicalSubExpression) || + (!shouldInlineLogicalExpression(n) && shouldIdentIfInlining) ) { return group(concat(parts)); } const rest = concat(parts.slice(1)); + // Break the closing paren to keep the chain right after it: + // (a && + // b && + // c + // ).call() + const breakClosingParen = + parent.type === "MemberExpression" && !parent.computed; + return group( concat([ // Don't include the initial expression in the indentation // level. The first item is guaranteed to be the first // left-most expression. parts.length > 0 ? parts[0] : "", - indent(rest) + indent(rest), + breakClosingParen ? softline : "" ]) ); } @@ -1244,8 +1263,6 @@ function genericPrintNoParens(path, options, print, args) { n.test.type === "JSXElement" || n.consequent.type === "JSXElement" || n.alternate.type === "JSXElement" || - parent.type === "JSXExpressionContainer" || - firstNonConditionalParent.type === "JSXExpressionContainer" || conditionalExpressionChainContainsJSX(lastConditionalParent) ) { jsxMode = true; @@ -1263,20 +1280,19 @@ function genericPrintNoParens(path, options, print, args) { ]); // The only things we don't wrap are: - // * Nested conditional expressions + // * Nested conditional expressions in alternates // * null - const shouldNotWrap = node => - node.type === "ConditionalExpression" || + const isNull = node => node.type === "NullLiteral" || (node.type === "Literal" && node.value === null); parts.push( " ? ", - shouldNotWrap(n.consequent) + isNull(n.consequent) ? path.call(print, "consequent") : wrap(path.call(print, "consequent")), " : ", - shouldNotWrap(n.alternate) + n.alternate.type === "ConditionalExpression" || isNull(n.alternate) ? path.call(print, "alternate") : wrap(path.call(print, "alternate")) ); @@ -1302,10 +1318,19 @@ function genericPrintNoParens(path, options, print, args) { ? parent === firstNonConditionalParent ? group(doc) : doc : group(doc); // Always group in normal mode. + // Break the closing paren to keep the chain right after it: + // (a + // ? b + // : c + // ).call() + const breakClosingParen = + !jsxMode && parent.type === "MemberExpression" && !parent.computed; + return maybeGroup( concat([ path.call(print, "test"), - forceNoIndent ? concat(parts) : indent(concat(parts)) + forceNoIndent ? concat(parts) : indent(concat(parts)), + breakClosingParen ? softline : "" ]) ); } @@ -3694,12 +3719,7 @@ function printMemberChain(path, options, print) { // If we only have a single `.`, we shouldn't do anything fancy and just // render everything concatenated together. - if ( - groups.length <= cutoff && - !hasComment && - // (a || b).map() should be break before .map() instead of || - groups[0][0].node.type !== "LogicalExpression" - ) { + if (groups.length <= cutoff && !hasComment) { return group(oneLine); } diff --git a/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap b/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap index dcb11e3f0..5c4ba464f 100644 --- a/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap +++ b/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap @@ -6,6 +6,14 @@ function f() { entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() ) } + +function f() { + const appEntitys = getAppEntitys(loadObject).map( + entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() && { + id: entity.id + } + ) +} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ function f() { const appEntitys = getAppEntitys(loadObject).filter( @@ -17,6 +25,18 @@ function f() { ); } +function f() { + const appEntitys = getAppEntitys(loadObject).map( + entity => + entity && + entity.isInstallAvailable() && + !entity.isQueue() && + entity.isDisabled() && { + id: entity.id + } + ); +} + `; exports[`bitwise-flags.js 1`] = ` @@ -134,12 +154,42 @@ prevState = prevState || { selectedCatalog: null, }; +prevState = prevState || + defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, + }; + this.steps = steps || [ { name: 'mock-module', path: '/nux/mock-module', }, ]; + +const create = () => { + const result = doSomething(); + return ( + shouldReturn && + result.ok && { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt + } + ); +} + +const obj = { + state: shouldHaveState && + stateIsOK && { + loadState: LOADED, + opened: false + }, + loaded: true +} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ prevState = prevState || { catalogs: [], @@ -149,6 +199,15 @@ prevState = prevState || { selectedCatalog: null }; +prevState = prevState || + defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: "", + selectedCatalog: null + }; + this.steps = steps || [ { name: "mock-module", @@ -156,6 +215,27 @@ this.steps = steps || [ } ]; +const create = () => { + const result = doSomething(); + return ( + shouldReturn && + result.ok && { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt + } + ); +}; + +const obj = { + state: shouldHaveState && + stateIsOK && { + loadState: LOADED, + opened: false + }, + loaded: true +}; + `; exports[`jsx_parent.js 1`] = ` @@ -172,6 +252,21 @@ exports[`jsx_parent.js 1`] = ` diffUpdateMessageInput != null && this.state.isUpdateMessageEmpty} ; + +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null &&
Text
} +
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null && ( +
+ Text +
+ )} +
; + `; exports[`math.js 1`] = ` @@ -238,6 +352,46 @@ x & (y >> z); `; +exports[`return.js 1`] = ` +function foo() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right; +} + +function foo() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right + ? true + : false; +} + +function foo() { + return this.calculate().compute().first.numberOfThings > this.calculate().compute().last.numberOfThings + ? true + : false; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo() { + return ( + this.hasPlugin("dynamicImports") && + this.lookahead().type === tt.parenLeft.right + ); +} + +function foo() { + return this.hasPlugin("dynamicImports") && + this.lookahead().type === tt.parenLeft.right + ? true + : false; +} + +function foo() { + return this.calculate().compute().first.numberOfThings > + this.calculate().compute().last.numberOfThings + ? true + : false; +} + +`; + exports[`short-right.js 1`] = ` this._cumulativeHeights && Math.abs( diff --git a/tests/binary-expressions/arrow.js b/tests/binary-expressions/arrow.js index 2fbafa9f0..a59339032 100644 --- a/tests/binary-expressions/arrow.js +++ b/tests/binary-expressions/arrow.js @@ -3,3 +3,11 @@ function f() { entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() ) } + +function f() { + const appEntitys = getAppEntitys(loadObject).map( + entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() && { + id: entity.id + } + ) +} diff --git a/tests/binary-expressions/inline-object-array.js b/tests/binary-expressions/inline-object-array.js index 76d47eabc..4aa40348c 100644 --- a/tests/binary-expressions/inline-object-array.js +++ b/tests/binary-expressions/inline-object-array.js @@ -6,9 +6,39 @@ prevState = prevState || { selectedCatalog: null, }; +prevState = prevState || + defaultState || { + catalogs: [], + loadState: LOADED, + opened: false, + searchQuery: '', + selectedCatalog: null, + }; + this.steps = steps || [ { name: 'mock-module', path: '/nux/mock-module', }, ]; + +const create = () => { + const result = doSomething(); + return ( + shouldReturn && + result.ok && { + status: "ok", + createdAt: result.createdAt, + updatedAt: result.updatedAt + } + ); +} + +const obj = { + state: shouldHaveState && + stateIsOK && { + loadState: LOADED, + opened: false + }, + loaded: true +} diff --git a/tests/binary-expressions/jsx_parent.js b/tests/binary-expressions/jsx_parent.js index 0339b5146..9340fcf68 100644 --- a/tests/binary-expressions/jsx_parent.js +++ b/tests/binary-expressions/jsx_parent.js @@ -11,3 +11,18 @@ diffUpdateMessageInput != null && this.state.isUpdateMessageEmpty}
; + +
; + +
+ {!isJellyfishEnabled && + diffUpdateMessageInput != null &&
Text
} +
; diff --git a/tests/binary-expressions/return.js b/tests/binary-expressions/return.js new file mode 100644 index 000000000..44ba5b067 --- /dev/null +++ b/tests/binary-expressions/return.js @@ -0,0 +1,15 @@ +function foo() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right; +} + +function foo() { + return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right + ? true + : false; +} + +function foo() { + return this.calculate().compute().first.numberOfThings > this.calculate().compute().last.numberOfThings + ? true + : false; +} diff --git a/tests/comments/__snapshots__/jsfmt.spec.js.snap b/tests/comments/__snapshots__/jsfmt.spec.js.snap index 064265e30..7fab11669 100644 --- a/tests/comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/comments/__snapshots__/jsfmt.spec.js.snap @@ -328,10 +328,45 @@ else if (4) { else { } -if (1) -{} +if (5) // comment +true + +if (6) // comment +{true} +else if (7) // comment +true else // comment -{} +{true} + +if (8) // comment +// comment +{true} +else if (9) // comment +// comment +true +else // comment +// comment +{true} + +if (10) /* comment */ // comment +{true} +else if (11) /* comment */ +true +else if (12) // comment /* comment */ // comment +true +else if (13) /* comment */ /* comment */ // comment +true +else /* comment */ +{true} + +if (14) // comment +/* comment */ +// comment +{true} +else if (15) // comment +/* comment */ +/* comment */ // comment +true ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (1) { // comment @@ -352,11 +387,63 @@ else if (4) { // comment } -if (1) { -} else { +if (5) // comment + true; + +if (6) { + // comment + true; +} else if (7) + // comment + true; +else { + // comment + true; } +if (8) { + // comment + // comment + true; +} else if (9) + // comment + // comment + true; +else { + // comment + // comment + true; +} + +if (10) { + /* comment */ // comment + true; +} else if (11) + /* comment */ + true; +else if (12) + // comment /* comment */ // comment + true; +else if (13) + /* comment */ /* comment */ // comment + true; +else { + /* comment */ + true; +} + +if (14) { + // comment + /* comment */ + // comment + true; +} else if (15) + // comment + /* comment */ + /* comment */ // comment + true; + `; exports[`issues.js 1`] = ` diff --git a/tests/comments/if.js b/tests/comments/if.js index 26f895ba4..ff4043ec1 100644 --- a/tests/comments/if.js +++ b/tests/comments/if.js @@ -20,7 +20,42 @@ else if (4) { else { } -if (1) -{} +if (5) // comment +true + +if (6) // comment +{true} +else if (7) // comment +true else // comment -{} +{true} + +if (8) // comment +// comment +{true} +else if (9) // comment +// comment +true +else // comment +// comment +{true} + +if (10) /* comment */ // comment +{true} +else if (11) /* comment */ +true +else if (12) // comment /* comment */ // comment +true +else if (13) /* comment */ /* comment */ // comment +true +else /* comment */ +{true} + +if (14) // comment +/* comment */ +// comment +{true} +else if (15) // comment +/* comment */ +/* comment */ // comment +true diff --git a/tests/if/__snapshots__/jsfmt.spec.js.snap b/tests/if/__snapshots__/jsfmt.spec.js.snap index 7707ed254..50598c4e4 100644 --- a/tests/if/__snapshots__/jsfmt.spec.js.snap +++ b/tests/if/__snapshots__/jsfmt.spec.js.snap @@ -54,6 +54,24 @@ async function f() { } } +async function f() { + if (untrackedChoice === 0) /* Cancel */ + null; + else if (untrackedChoice === 1) /* Add */ + shouldAmend = true; + else if (untrackedChoice === 2) /* Allow Untracked */ + allowUntracked = true; +} + +async function f() { + if (untrackedChoice === 0) /* Cancel */ // Cancel + null; + else if (untrackedChoice === 1) /* Add */ // Add + shouldAmend = true; + else if (untrackedChoice === 2) /* Allow Untracked */ // Allow Untracked + allowUntracked = true; +} + async function f() { if (untrackedChoice === 0) /* Cancel */ { @@ -92,6 +110,30 @@ async function f() { } } +async function f() { + if (untrackedChoice === 0) + /* Cancel */ + null; + else if (untrackedChoice === 1) + /* Add */ + shouldAmend = true; + else if (untrackedChoice === 2) + /* Allow Untracked */ + allowUntracked = true; +} + +async function f() { + if (untrackedChoice === 0) + /* Cancel */ // Cancel + null; + else if (untrackedChoice === 1) + /* Add */ // Add + shouldAmend = true; + else if (untrackedChoice === 2) + /* Allow Untracked */ // Allow Untracked + allowUntracked = true; +} + async function f() { if (untrackedChoice === 0) { /* Cancel */ return null; diff --git a/tests/if/if_comments.js b/tests/if/if_comments.js index 2b3552999..2295fe836 100644 --- a/tests/if/if_comments.js +++ b/tests/if/if_comments.js @@ -9,6 +9,24 @@ async function f() { } } +async function f() { + if (untrackedChoice === 0) /* Cancel */ + null; + else if (untrackedChoice === 1) /* Add */ + shouldAmend = true; + else if (untrackedChoice === 2) /* Allow Untracked */ + allowUntracked = true; +} + +async function f() { + if (untrackedChoice === 0) /* Cancel */ // Cancel + null; + else if (untrackedChoice === 1) /* Add */ // Add + shouldAmend = true; + else if (untrackedChoice === 2) /* Allow Untracked */ // Allow Untracked + allowUntracked = true; +} + async function f() { if (untrackedChoice === 0) /* Cancel */ { diff --git a/tests/jsx/__snapshots__/jsfmt.spec.js.snap b/tests/jsx/__snapshots__/jsfmt.spec.js.snap index 8e0c4c78c..49b42843b 100644 --- a/tests/jsx/__snapshots__/jsfmt.spec.js.snap +++ b/tests/jsx/__snapshots__/jsfmt.spec.js.snap @@ -20,86 +20,20 @@ exports[`conditional-expression.js 1`] = ` // // test ? consequent : alternate; // -// We print a conditional expression in JSX mode if any of the following are -// true: -// * Its parent is a JSXExpressionContainer -// * Its test, consequent, or alternate are JSXElements -// * It is in a chain with other ConditionalExpressions, and the outermost -// one's parent is a JSXExpressionContainer -// * It is in a chain with other ConditionalExpressions, and any of the -// tests, consequents, or alternates of any of the ConditionalExpressions in -// the chain are JSXElements. +// We only print a conditional expression in JSX mode if its test, +// consequent, or alternate are JSXElements. // Otherwise, we print in normal mode. -// This ConditionalExpression does not meet any of the other criteria for -// printing in JSX mode, so it prints in normal mode. The line does not break. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// The line does not break. normalModeNonBreaking ? "a" : "b"; -// This ConditionalExpression does not meet any of the criteria to print in JSX -// mode, so it prints in normal mode. Its consequent is very long, so it breaks -// out to multiple lines. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// Its consequent is very long, so it breaks out to multiple lines. normalModeBreaking ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa : "c"; -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The line does not break, so it does not contain -// parens. -
- {a ? "b" : "c"} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the consequent is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : ( - "c" - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The consequent is long enough to break the line, but -// because the alternate is null, only the consequent is wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : null} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the alternate is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - "b" - ) : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The alternate is long enough to break the line, but -// because the consequent is null, only the alternate is wrapped in parens. -
- {a ? null : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the test is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa ? ( - "b" - ) : ( - "c" - )} -
; - // This ConditionalExpression prints in JSX mode because its test is a // JSXElement. It is non-breaking. // Note: I have never, ever seen someone use a JSXElement as the test in a @@ -153,19 +87,6 @@ jsxModeFromElementBreaking ? ( {a ? "a" : b ? "b" : "c"}
; -// This chain of ConditionalExpressions prints in JSX mode because the parent of -// the outermost ConditionalExpression is a JSXExpressionContainer. It is -// breaking. -
- {a ? ( - "a" - ) : b ? ( - "b" - ) : ( - thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo - )} -
; - // This chain of ConditionalExpressions prints in JSX mode because there is a // JSX element somewhere in the chain. It is non-breaking. cable ? "satellite" : public ? "affairs" : network ? : "dunno"; @@ -197,6 +118,20 @@ cable ? ( ) : affairs ? ( "network" ) : "dunno"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain. It is breaking; notice the consequents +// and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // There are two ways to print ConditionalExpressions: "normal mode" and // "JSX mode". This is normal mode (when breaking): @@ -217,84 +152,20 @@ cable ? ( // // test ? consequent : alternate; // -// We print a conditional expression in JSX mode if any of the following are -// true: -// * Its parent is a JSXExpressionContainer -// * Its test, consequent, or alternate are JSXElements -// * It is in a chain with other ConditionalExpressions, and the outermost -// one's parent is a JSXExpressionContainer -// * It is in a chain with other ConditionalExpressions, and any of the -// tests, consequents, or alternates of any of the ConditionalExpressions in -// the chain are JSXElements. +// We only print a conditional expression in JSX mode if its test, +// consequent, or alternate are JSXElements. // Otherwise, we print in normal mode. -// This ConditionalExpression does not meet any of the other criteria for -// printing in JSX mode, so it prints in normal mode. The line does not break. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// The line does not break. normalModeNonBreaking ? "a" : "b"; -// This ConditionalExpression does not meet any of the criteria to print in JSX -// mode, so it prints in normal mode. Its consequent is very long, so it breaks -// out to multiple lines. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// Its consequent is very long, so it breaks out to multiple lines. normalModeBreaking ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa : "c"; -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The line does not break, so it does not contain -// parens. -
{a ? "b" : "c"}
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the consequent is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : ( - "c" - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The consequent is long enough to break the line, but -// because the alternate is null, only the consequent is wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : null} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the alternate is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - "b" - ) : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The alternate is long enough to break the line, but -// because the consequent is null, only the alternate is wrapped in parens. -
- {a ? null : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the test is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa ? ( - "b" - ) : ( - "c" - )} -
; - // This ConditionalExpression prints in JSX mode because its test is a // JSXElement. It is non-breaking. // Note: I have never, ever seen someone use a JSXElement as the test in a @@ -352,19 +223,6 @@ jsxModeFromElementBreaking ? ( // non-breaking.
{a ? "a" : b ? "b" : "c"}
; -// This chain of ConditionalExpressions prints in JSX mode because the parent of -// the outermost ConditionalExpression is a JSXExpressionContainer. It is -// breaking. -
- {a ? ( - "a" - ) : b ? ( - "b" - ) : ( - thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo - )} -
; - // This chain of ConditionalExpressions prints in JSX mode because there is a // JSX element somewhere in the chain. It is non-breaking. cable ? "satellite" : public ? "affairs" : network ? : "dunno"; @@ -405,6 +263,20 @@ cable ? ( "dunno" ); +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain. It is breaking; notice the consequents +// and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; + `; exports[`expression.js 1`] = ` @@ -656,6 +528,14 @@ exports[`logical-expression.js 1`] = ` {a && }
; +
+ {a && make this text just so long enough to break this to the next line} +
; + +
+ {a && b && make this text just so long enough to break this to the next line} +
; +
{a &&
@@ -672,6 +552,23 @@ exports[`logical-expression.js 1`] = `
{a && }
; +
+ {a && ( + + make this text just so long enough to break this to the next line + + )} +
; + +
+ {a && + b && ( + + make this text just so long enough to break this to the next line + + )} +
; +
{a && ( diff --git a/tests/jsx/conditional-expression.js b/tests/jsx/conditional-expression.js index 1ca836cd3..5266662a9 100644 --- a/tests/jsx/conditional-expression.js +++ b/tests/jsx/conditional-expression.js @@ -17,86 +17,20 @@ // // test ? consequent : alternate; // -// We print a conditional expression in JSX mode if any of the following are -// true: -// * Its parent is a JSXExpressionContainer -// * Its test, consequent, or alternate are JSXElements -// * It is in a chain with other ConditionalExpressions, and the outermost -// one's parent is a JSXExpressionContainer -// * It is in a chain with other ConditionalExpressions, and any of the -// tests, consequents, or alternates of any of the ConditionalExpressions in -// the chain are JSXElements. +// We only print a conditional expression in JSX mode if its test, +// consequent, or alternate are JSXElements. // Otherwise, we print in normal mode. -// This ConditionalExpression does not meet any of the other criteria for -// printing in JSX mode, so it prints in normal mode. The line does not break. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// The line does not break. normalModeNonBreaking ? "a" : "b"; -// This ConditionalExpression does not meet any of the criteria to print in JSX -// mode, so it prints in normal mode. Its consequent is very long, so it breaks -// out to multiple lines. +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// Its consequent is very long, so it breaks out to multiple lines. normalModeBreaking ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa : "c"; -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The line does not break, so it does not contain -// parens. -
- {a ? "b" : "c"} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the consequent is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : ( - "c" - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The consequent is long enough to break the line, but -// because the alternate is null, only the consequent is wrapped in parens. -
- {a ? ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - ) : null} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the alternate is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {a ? ( - "b" - ) : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. The alternate is long enough to break the line, but -// because the consequent is null, only the alternate is wrapped in parens. -
- {a ? null : ( - johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa - )} -
; - -// This ConditionalExpression prints in JSX mode because its parent is a -// JSXExpressionContainer. Because the test is long enough to break the -// line, both its consequent and alternate break out and are wrapped in parens. -
- {johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa ? ( - "b" - ) : ( - "c" - )} -
; - // This ConditionalExpression prints in JSX mode because its test is a // JSXElement. It is non-breaking. // Note: I have never, ever seen someone use a JSXElement as the test in a @@ -150,19 +84,6 @@ jsxModeFromElementBreaking ? ( {a ? "a" : b ? "b" : "c"}
; -// This chain of ConditionalExpressions prints in JSX mode because the parent of -// the outermost ConditionalExpression is a JSXExpressionContainer. It is -// breaking. -
- {a ? ( - "a" - ) : b ? ( - "b" - ) : ( - thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo - )} -
; - // This chain of ConditionalExpressions prints in JSX mode because there is a // JSX element somewhere in the chain. It is non-breaking. cable ? "satellite" : public ? "affairs" : network ? : "dunno"; @@ -194,3 +115,17 @@ cable ? ( ) : affairs ? ( "network" ) : "dunno"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain. It is breaking; notice the consequents +// and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; diff --git a/tests/jsx/logical-expression.js b/tests/jsx/logical-expression.js index 269a2e2df..948f1cfa0 100644 --- a/tests/jsx/logical-expression.js +++ b/tests/jsx/logical-expression.js @@ -14,6 +14,14 @@ {a && }
; +
+ {a && make this text just so long enough to break this to the next line} +
; + +
+ {a && b && make this text just so long enough to break this to the next line} +
; +
{a &&
diff --git a/tests/member/__snapshots__/jsfmt.spec.js.snap b/tests/member/__snapshots__/jsfmt.spec.js.snap index e2dfaec76..3a1882958 100644 --- a/tests/member/__snapshots__/jsfmt.spec.js.snap +++ b/tests/member/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`conditional.js 1`] = ` +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.prop; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser) +).prop; + +`; + exports[`expand.js 1`] = ` const veryVeryVeryVeryVeryVeryVeryLong = doc.expandedStates[doc.expandedStates.length - 1]; const small = doc.expandedStates[doc.expandedStates.length - 1]; @@ -53,3 +66,17 @@ const promises = [ ]; `; + +exports[`logical.js 1`] = ` +(veryLongVeryLongVeryLong || e).prop; + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).prop; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(veryLongVeryLongVeryLong || e).prop; + +(veryLongVeryLongVeryLong || + anotherVeryLongVeryLongVeryLong || + veryVeryVeryLongError +).prop; + +`; diff --git a/tests/member/conditional.js b/tests/member/conditional.js new file mode 100644 index 000000000..916a775fd --- /dev/null +++ b/tests/member/conditional.js @@ -0,0 +1,4 @@ +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.prop; diff --git a/tests/member/logical.js b/tests/member/logical.js new file mode 100644 index 000000000..e9eb10f8f --- /dev/null +++ b/tests/member/logical.js @@ -0,0 +1,3 @@ +(veryLongVeryLongVeryLong || e).prop; + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).prop; diff --git a/tests/method-chain/__snapshots__/jsfmt.spec.js.snap b/tests/method-chain/__snapshots__/jsfmt.spec.js.snap index da56e5a02..4c0f23729 100644 --- a/tests/method-chain/__snapshots__/jsfmt.spec.js.snap +++ b/tests/method-chain/__snapshots__/jsfmt.spec.js.snap @@ -416,6 +416,67 @@ exports[`computed-merge.js 1`] = ` `; +exports[`conditional.js 1`] = ` +(a ? b : c).d(); + +(a ? b : c).d().e(); + +(a ? b : c).d().e().f(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.map(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.map().filter(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser)) +.map(); + +object[valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser)] +.map(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(a ? b : c).d(); + +(a ? b : c).d().e(); + +(a ? b : c) + .d() + .e() + .f(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser) +).map(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser) +) + .map() + .filter(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser) +).map(); + +object[ + valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser) +].map(); + +`; + exports[`first_long.js 1`] = ` export default function theFunction(action$, store) { return action$.ofType(THE_ACTION).switchMap(action => Observable @@ -511,9 +572,35 @@ Object.keys( exports[`logical.js 1`] = ` (veryLongVeryLongVeryLong || e).map(tickets => TicketRecord.createFromSomeLongString()); + +(veryLongVeryLongVeryLong || e).map(tickets => + TicketRecord.createFromSomeLongString()).filter(obj => !!obj); + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => + TicketRecord.createFromSomeLongString()); + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => + TicketRecord.createFromSomeLongString()).filter(obj => !!obj); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(veryLongVeryLongVeryLong || e).map(tickets => + TicketRecord.createFromSomeLongString() +); + (veryLongVeryLongVeryLong || e) - .map(tickets => TicketRecord.createFromSomeLongString()); + .map(tickets => TicketRecord.createFromSomeLongString()) + .filter(obj => !!obj); + +(veryLongVeryLongVeryLong || + anotherVeryLongVeryLongVeryLong || + veryVeryVeryLongError +).map(tickets => TicketRecord.createFromSomeLongString()); + +(veryLongVeryLongVeryLong || + anotherVeryLongVeryLongVeryLong || + veryVeryVeryLongError +) + .map(tickets => TicketRecord.createFromSomeLongString()) + .filter(obj => !!obj); `; diff --git a/tests/method-chain/conditional.js b/tests/method-chain/conditional.js new file mode 100644 index 000000000..d7e61deeb --- /dev/null +++ b/tests/method-chain/conditional.js @@ -0,0 +1,25 @@ +(a ? b : c).d(); + +(a ? b : c).d().e(); + +(a ? b : c).d().e().f(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.map(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(this.defaultUser)) +.map().filter(); + +(valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser)) +.map(); + +object[valid + ? helper.responseBody(this.currentUser) + : helper.responseBody(defaultUser)] +.map(); diff --git a/tests/method-chain/logical.js b/tests/method-chain/logical.js index a7ab0442d..6d76f5cd9 100644 --- a/tests/method-chain/logical.js +++ b/tests/method-chain/logical.js @@ -1,2 +1,11 @@ (veryLongVeryLongVeryLong || e).map(tickets => TicketRecord.createFromSomeLongString()); + +(veryLongVeryLongVeryLong || e).map(tickets => + TicketRecord.createFromSomeLongString()).filter(obj => !!obj); + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => + TicketRecord.createFromSomeLongString()); + +(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => + TicketRecord.createFromSomeLongString()).filter(obj => !!obj); diff --git a/tests/multiparser_js_graphql/__snapshots__/jsfmt.spec.js.snap b/tests/multiparser_js_graphql/__snapshots__/jsfmt.spec.js.snap index 3719f9e4d..ee69af2e7 100644 --- a/tests/multiparser_js_graphql/__snapshots__/jsfmt.spec.js.snap +++ b/tests/multiparser_js_graphql/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`graphql.js 1`] = ` +graphql(schema, \` +mutation MarkReadNotificationMutation( + $input + : MarkReadNotificationData! + ) +{ markReadNotification(data: $input ) { notification {seenState} } }\`) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +graphql( + schema, + \` + mutation MarkReadNotificationMutation($input: MarkReadNotificationData!) { + markReadNotification(data: $input) { + notification { + seenState + } + } + } + \` +); + +`; + exports[`graphql-tag.js 1`] = ` import gql from "graphql-tag"; diff --git a/tests/multiparser_js_graphql/graphql.js b/tests/multiparser_js_graphql/graphql.js new file mode 100644 index 000000000..d41e7ac0b --- /dev/null +++ b/tests/multiparser_js_graphql/graphql.js @@ -0,0 +1,6 @@ +graphql(schema, ` +mutation MarkReadNotificationMutation( + $input + : MarkReadNotificationData! + ) +{ markReadNotification(data: $input ) { notification {seenState} } }`) diff --git a/tests/require-pragma/__snapshots__/jsfmt.spec.js.snap b/tests/require-pragma/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..66392b09f --- /dev/null +++ b/tests/require-pragma/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`module-with-pragma.js 1`] = ` +/** + * @flow + * @format + */ + +function foo(bar) + + +{ + + return bar + + 3 + + 4; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + * @format + */ + +function foo(bar) { + return bar + 3 + 4; +} + +`; + +exports[`module-without-pragma.js 1`] = ` +/** + * @flow + */ + +function foo(bar) + + +{ + + return bar + + 3 + + 4; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ + +function foo(bar) + + +{ + + return bar + + 3 + + 4; +} + +`; diff --git a/tests/require-pragma/jsfmt.spec.js b/tests/require-pragma/jsfmt.spec.js new file mode 100644 index 000000000..61c7d29f1 --- /dev/null +++ b/tests/require-pragma/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname, { requirePragma: true }); diff --git a/tests/require-pragma/module-with-pragma.js b/tests/require-pragma/module-with-pragma.js new file mode 100644 index 000000000..79499ba96 --- /dev/null +++ b/tests/require-pragma/module-with-pragma.js @@ -0,0 +1,14 @@ +/** + * @flow + * @format + */ + +function foo(bar) + + +{ + + return bar + + 3 + + 4; +} diff --git a/tests/require-pragma/module-without-pragma.js b/tests/require-pragma/module-without-pragma.js new file mode 100644 index 000000000..8ece37915 --- /dev/null +++ b/tests/require-pragma/module-without-pragma.js @@ -0,0 +1,13 @@ +/** + * @flow + */ + +function foo(bar) + + +{ + + return bar + + 3 + + 4; +} diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap index 81614cbad..c06842892 100644 --- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap @@ -59,6 +59,8 @@ Other options: --no-color Do not colorize error messages. --help or -h Show help. + --require-pragma Require either '@prettier' or '@format' to be present in the file's first docblock comment + in order for it to be formatted. --stdin Force reading input from stdin. --stdin-filepath Path to the file to pretend that stdin comes from. --version or -v Print Prettier version. @@ -126,6 +128,8 @@ Other options: --no-color Do not colorize error messages. --help or -h Show help. + --require-pragma Require either '@prettier' or '@format' to be present in the file's first docblock comment + in order for it to be formatted. --stdin Force reading input from stdin. --stdin-filepath Path to the file to pretend that stdin comes from. --version or -v Print Prettier version. diff --git a/tests_integration/__tests__/__snapshots__/ignore-absolute-path.js.snap b/tests_integration/__tests__/__snapshots__/ignore-absolute-path.js.snap new file mode 100644 index 000000000..a396d0f89 --- /dev/null +++ b/tests_integration/__tests__/__snapshots__/ignore-absolute-path.js.snap @@ -0,0 +1,6 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`support absolute filename 1`] = ` +"regular-module.js +" +`; diff --git a/tests_integration/__tests__/ignore-absolute-path.js b/tests_integration/__tests__/ignore-absolute-path.js new file mode 100644 index 000000000..8e46de3f3 --- /dev/null +++ b/tests_integration/__tests__/ignore-absolute-path.js @@ -0,0 +1,16 @@ +"use strict"; + +const path = require("path"); +const runPrettier = require("../runPrettier"); + +test("support absolute filename", () => { + const result = runPrettier("cli/ignore-absolute-path", [ + path.resolve(__dirname, "../cli/ignore-absolute-path/ignored/module.js"), + path.resolve(__dirname, "../cli/ignore-absolute-path/depth1/ignored/*.js"), + path.resolve(__dirname, "../cli/ignore-absolute-path/regular-module.js"), + "-l" + ]); + + expect(result.stdout).toMatchSnapshot(); + expect(result.status).toEqual(1); +}); diff --git a/tests_integration/cli/ignore-absolute-path/.prettierignore b/tests_integration/cli/ignore-absolute-path/.prettierignore new file mode 100644 index 000000000..c51aa823b --- /dev/null +++ b/tests_integration/cli/ignore-absolute-path/.prettierignore @@ -0,0 +1,2 @@ +/ignored/ +depth1/ignored/ diff --git a/tests_integration/cli/ignore-absolute-path/depth1/ignored/module.js b/tests_integration/cli/ignore-absolute-path/depth1/ignored/module.js new file mode 100644 index 000000000..ad9a93a7c --- /dev/null +++ b/tests_integration/cli/ignore-absolute-path/depth1/ignored/module.js @@ -0,0 +1 @@ +'use strict'; diff --git a/tests_integration/cli/ignore-absolute-path/ignored/module.js b/tests_integration/cli/ignore-absolute-path/ignored/module.js new file mode 100644 index 000000000..ad9a93a7c --- /dev/null +++ b/tests_integration/cli/ignore-absolute-path/ignored/module.js @@ -0,0 +1 @@ +'use strict'; diff --git a/tests_integration/cli/ignore-absolute-path/regular-module.js b/tests_integration/cli/ignore-absolute-path/regular-module.js new file mode 100644 index 000000000..ad9a93a7c --- /dev/null +++ b/tests_integration/cli/ignore-absolute-path/regular-module.js @@ -0,0 +1 @@ +'use strict'; diff --git a/tests_integration/cwd-serializer.js b/tests_integration/cwd-serializer.js index 88027d12e..4cd7009ab 100644 --- a/tests_integration/cwd-serializer.js +++ b/tests_integration/cwd-serializer.js @@ -4,5 +4,5 @@ module.exports = { test: value => typeof value === "string" && value.indexOf(process.cwd()) !== -1, print: (value, serializer) => - serializer(value.replace(process.cwd(), "")) + serializer(value.replace(process.cwd(), "").replace(/\\/g, "/")) }; diff --git a/yarn.lock b/yarn.lock index fbdccb6d7..da7e212c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2258,6 +2258,10 @@ jest-docblock@^20.0.1, jest-docblock@^20.0.3: version "20.0.3" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.0.3.tgz#17bea984342cc33d83c50fbe1545ea0efaa44712" +jest-docblock@^21.0.2: + version "21.0.2" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.0.2.tgz#66f69ddb440799fc32f91d0ac3d8d35e99e2032f" + jest-environment-jsdom@^20.0.3: version "20.0.3" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz#048a8ac12ee225f7190417713834bb999787de99"