From 9a1e408a3ffa8a8bf0cf2e4c4ce05cd4abbdfbf9 Mon Sep 17 00:00:00 2001 From: Stephen Scott Date: Sun, 26 Nov 2017 15:51:48 -0700 Subject: [PATCH 1/9] Add option and specs (no implementation yet) These new snapshots are from https://github.com/prettier/prettier/pull/2676 --- docs/options.md | 13 + src/cli-constant.js | 17 + src/options.js | 3 +- .../__snapshots__/jsfmt.spec.js.snap | 95 ++++ tests/arrow-call/jsfmt.spec.js | 1 + tests/arrows/__snapshots__/jsfmt.spec.js.snap | 510 ++++++++++++++++++ tests/arrows/arrow_function_expression.js | 4 + tests/arrows/currying.js | 6 + tests/arrows/jsfmt.spec.js | 7 +- tests/arrows/parens.js | 15 + .../__snapshots__/early-exit.js.snap | 24 + 11 files changed, 693 insertions(+), 2 deletions(-) create mode 100644 tests/arrows/parens.js diff --git a/docs/options.md b/docs/options.md index 8a9cfee7a..b3d83cfd4 100644 --- a/docs/options.md +++ b/docs/options.md @@ -96,6 +96,19 @@ Put the `>` of a multi-line JSX element at the end of the last line instead of b | ------- | ------------------------- | ---------------------------- | | `false` | `--jsx-bracket-same-line` | `jsxBracketSameLine: ` | +# Arrow Function Parentheses + +Include parentheses around a sole arrow function parameter. + +Valid options: + +* `"avoid"` - Omit parens when possible. Example: `x => x` +* `"always"` - Always include parens. Example: `(x) => x` + +| Default | CLI Override | API Override | +| --------- | --------------------------------------------------------- | ------------------------------------------------------- | +| `"avoid"` | --arrow-function-parens | arrowFunctionParentheses: "" | + ## Range Format only a segment of a file. diff --git a/src/cli-constant.js b/src/cli-constant.js index 92ce7e371..376c718b9 100644 --- a/src/cli-constant.js +++ b/src/cli-constant.js @@ -77,6 +77,23 @@ const categoryOrder = [ * Note: The options below are sorted alphabetically. */ const detailedOptions = normalizeDetailedOptions({ + "arrow-function-parentheses": { + type: "choice", + category: CATEGORY_FORMAT, + forwardToApi: true, + description: "Include parentheses around a sole arrow function parameter.", + default: "avoid", + choices: [ + { + value: "avoid", + description: "Omit parens when possible. Example: `x => x`" + }, + { + value: "always", + description: "Always include parens. Example: `(x) => x`" + } + ] + }, "bracket-spacing": { type: "boolean", category: CATEGORY_FORMAT, diff --git a/src/options.js b/src/options.js index 19c34ab80..87ba34028 100644 --- a/src/options.js +++ b/src/options.js @@ -21,7 +21,8 @@ const defaults = { insertPragma: false, requirePragma: false, semi: true, - proseWrap: true + proseWrap: true, + arrowFunctionParentheses: "avoid" }; const exampleConfig = Object.assign({}, defaults, { diff --git a/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap b/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap index 0597d87a7..006da744c 100644 --- a/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap +++ b/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap @@ -189,3 +189,98 @@ const composition = (ViewComponent, ContainerComponent) => }; `; + +exports[`arrow_call.js 3`] = ` +const testResults = results.testResults.map(testResult => + formatResult(testResult, formatter, reporter) +); + +it('mocks regexp instances', () => { + expect( + () => moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)), + ).not.toThrow(); +}); + +expect(() => asyncRequest({ url: "/test-endpoint" })) + .toThrowError(/Required parameter/); + +expect(() => asyncRequest({ url: "/test-endpoint-but-with-a-long-url" })) + .toThrowError(/Required parameter/); + +expect(() => asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" })) + .toThrowError(/Required parameter/); + +expect(() => asyncRequest({ type: "foo", url: "/test-endpoint" })) + .not.toThrowError(); + +expect(() => asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" })) + .not.toThrowError(); + +const a = Observable + .fromPromise(axiosInstance.post('/carts/mine')) + .map((response) => response.data) + +const b = Observable.fromPromise(axiosInstance.get(url)) + .map((response) => response.data) + +func( + veryLoooooooooooooooooooooooongName, + veryLooooooooooooooooooooooooongName => + veryLoooooooooooooooongName.something() +); + +const composition = (ViewComponent, ContainerComponent) => + class extends React.Component { + static propTypes = {}; + }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const testResults = results.testResults.map(testResult => + formatResult(testResult, formatter, reporter) +); + +it("mocks regexp instances", () => { + expect(() => + moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)) + ).not.toThrow(); +}); + +expect(() => asyncRequest({ url: "/test-endpoint" })).toThrowError( + /Required parameter/ +); + +expect(() => + asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }) +).toThrowError(/Required parameter/); + +expect(() => + asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }) +).toThrowError(/Required parameter/); + +expect(() => + asyncRequest({ type: "foo", url: "/test-endpoint" }) +).not.toThrowError(); + +expect(() => + asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }) +).not.toThrowError(); + +const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map( + response => response.data +); + +const b = Observable.fromPromise(axiosInstance.get(url)).map( + response => response.data +); + +func( + veryLoooooooooooooooooooooooongName, + veryLooooooooooooooooooooooooongName => + veryLoooooooooooooooongName.something() +); + +const composition = (ViewComponent, ContainerComponent) => + class extends React.Component { + static propTypes = {}; + }; + +`; diff --git a/tests/arrow-call/jsfmt.spec.js b/tests/arrow-call/jsfmt.spec.js index 4e02696c9..db45d9868 100644 --- a/tests/arrow-call/jsfmt.spec.js +++ b/tests/arrow-call/jsfmt.spec.js @@ -1,2 +1,3 @@ run_spec(__dirname, null, ["typescript"]); run_spec(__dirname, { trailingComma: "all" }, ["typescript"]); +run_spec(__dirname, { arrowFunctionParentheses: "always" }, ["typescript"]); diff --git a/tests/arrows/__snapshots__/jsfmt.spec.js.snap b/tests/arrows/__snapshots__/jsfmt.spec.js.snap index 065c38271..c4794e33f 100644 --- a/tests/arrows/__snapshots__/jsfmt.spec.js.snap +++ b/tests/arrows/__snapshots__/jsfmt.spec.js.snap @@ -32,6 +32,10 @@ x => (y = z); x => (y += z); f(a => ({})) + 1; (a => ({})) || 0; +a = b => c; +a = b => { + return c +}; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (a => {}).length; typeof (() => {}); @@ -65,6 +69,86 @@ x => (y = z); x => (y += z); f(a => ({})) + 1; (a => ({})) || 0; +a = b => c; +a = b => { + return c; +}; + +`; + +exports[`arrow_function_expression.js 2`] = ` +(a => {}).length +typeof (() => {}); +export default (() => {})(); +(() => {})()\`\`; +(() => {})\`\`; +new (() => {}); +if ((() => {}) ? 1 : 0) {} +let f = () => ({}()) +let a = () => ({} instanceof a); +a = () => ({} && a); +a = () => ({}() && a); +a = () => ({} && a && b); +a = () => ({} + a); +a = () => ({}()() && a); +a = () => ({}.b && a); +a = () => ({}[b] && a); +a = () => ({}\`\` && a); +a = () => ({} = 0); +a = () => ({}, a); +a => a instanceof {}; +a => ({}().b && 0) +a => ({}().c = 0) +x => ({}()()) +x => ({}()\`\`) +x => ({}().b); +a = b => c; +a = (b?) => c; +x => (y = z); +x => (y += z); +f(a => ({})) + 1; +(a => ({})) || 0; +a = b => c; +a = b => { + return c +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(a => {}).length; +typeof (() => {}); +export default (() => {})(); +(() => {})()\`\`; +(() => {})\`\`; +new (() => {})(); +if ((() => {}) ? 1 : 0) { +} +let f = () => ({}()); +let a = () => ({} instanceof a); +a = () => ({} && a); +a = () => ({}() && a); +a = () => ({} && a && b); +a = () => ({} + a); +a = () => ({}()() && a); +a = () => ({}.b && a); +a = () => ({}[b] && a); +a = () => ({}\`\` && a); +a = () => ({} = 0); +a = () => ({}, a); +a => a instanceof {}; +a => ({}().b && 0); +a => ({}().c = 0); +x => ({}()()); +x => ({}()\`\`); +x => ({}().b); +a = b => c; +a = (b?) => c; +x => (y = z); +x => (y += z); +f(a => ({})) + 1; +(a => ({})) || 0; +a = b => c; +a = b => { + return c; +}; `; @@ -75,6 +159,13 @@ a = () => ({} = this); `; +exports[`block_like.js 2`] = ` +a = () => ({} = this); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +a = () => ({} = this); + +`; + exports[`call.js 1`] = ` Seq(typeDef.interface.groups).forEach(group => Seq(group.members).forEach((member, memberName) => @@ -248,6 +339,179 @@ fooooooooooooooooooooooooooooooooooooooooooooooooooo(action => next => `; +exports[`call.js 2`] = ` +Seq(typeDef.interface.groups).forEach(group => + Seq(group.members).forEach((member, memberName) => + markdownDoc( + member.doc, + { typePath: typePath.concat(memberName.slice(1)), + signatures: member.signatures } + ) + ) +) + +const promiseFromCallback = fn => + new Promise((resolve, reject) => + fn((err, result) => { + if (err) return reject(err); + return resolve(result); + }) + ); + +runtimeAgent.getProperties( + objectId, + false, // ownProperties + false, // accessorPropertiesOnly + false, // generatePreview + (error, properties, internalProperties) => { + return 1 + }, +); + +function render() { + return ( + + this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})} + /> + + ); +} + +function render() { + return ( + + + this.setState({ + progress: Math.round( + 100 * e.nativeEvent.loaded / e.nativeEvent.total, + ), + })} + /> + + ); +} + +function render() { + return ( + + + this.setState({ + progress: Math.round( + 100 * e.nativeEvent.loaded / e.nativeEvent.total, + ), + })} + /> + + ); +} + +jest.mock( + '../SearchSource', + () => class { + findMatchingTests(pattern) { + return {paths: []}; + } + }, +); + +fooooooooooooooooooooooooooooooooooooooooooooooooooo(action => next => + dispatch(action), +); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Seq(typeDef.interface.groups).forEach(group => + Seq(group.members).forEach((member, memberName) => + markdownDoc(member.doc, { + typePath: typePath.concat(memberName.slice(1)), + signatures: member.signatures + }) + ) +); + +const promiseFromCallback = fn => + new Promise((resolve, reject) => + fn((err, result) => { + if (err) return reject(err); + return resolve(result); + }) + ); + +runtimeAgent.getProperties( + objectId, + false, // ownProperties + false, // accessorPropertiesOnly + false, // generatePreview + (error, properties, internalProperties) => { + return 1; + } +); + +function render() { + return ( + + + this.setState({ + progress: Math.round( + 100 * e.nativeEvent.loaded / e.nativeEvent.total + ) + }) + } + /> + + ); +} + +function render() { + return ( + + + this.setState({ + progress: Math.round( + 100 * e.nativeEvent.loaded / e.nativeEvent.total + ) + }) + } + /> + + ); +} + +function render() { + return ( + + + this.setState({ + progress: Math.round( + 100 * e.nativeEvent.loaded / e.nativeEvent.total + ) + }) + } + /> + + ); +} + +jest.mock( + "../SearchSource", + () => + class { + findMatchingTests(pattern) { + return { paths: [] }; + } + } +); + +fooooooooooooooooooooooooooooooooooooooooooooooooooo(action => next => + dispatch(action) +); + +`; + exports[`comment.js 1`] = ` /** * Curried function that ends with a BEM CSS Selector @@ -313,11 +577,82 @@ export const bem = block => `; +exports[`comment.js 2`] = ` +/** + * Curried function that ends with a BEM CSS Selector + * + * @param {String} block - the BEM Block you'd like to select. + * @returns {Function} + */ +export const bem = block => + /** + * @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself. + * @returns {Function} + */ + element => + /** + * @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified. + * @returns {String} + */ + modifier => + [ + ".", + css(block), + element ? \`__\${css(element)}\` : "", + modifier ? \`--\${css(modifier)}\` : "" + ].join(""); + + {info.item.widget.missingProp}} + data={data} +/> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Curried function that ends with a BEM CSS Selector + * + * @param {String} block - the BEM Block you'd like to select. + * @returns {Function} + */ +export const bem = block => + /** + * @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself. + * @returns {Function} + */ + element => + /** + * @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified. + * @returns {String} + */ + modifier => + [ + ".", + css(block), + element ? \`__\${css(element)}\` : "", + modifier ? \`--\${css(modifier)}\` : "" + ].join(""); + + {info.item.widget.missingProp}} + data={data} +/>; + +`; + exports[`currying.js 1`] = ` const fn = b => c => d => { return 3; }; +const foo = (a, b) => c => d => { + return 3; +}; + +const bar = a => b => c => a + b + c + const mw = store => next => action => { return next(action) } @@ -330,6 +665,51 @@ const fn = b => c => d => { return 3; }; +const foo = (a, b) => c => d => { + return 3; +}; + +const bar = a => b => c => a + b + c; + +const mw = store => next => action => { + return next(action); +}; + +const middleware = options => (req, res, next) => { + // ... +}; + +`; + +exports[`currying.js 2`] = ` +const fn = b => c => d => { + return 3; +}; + +const foo = (a, b) => c => d => { + return 3; +}; + +const bar = a => b => c => a + b + c + +const mw = store => next => action => { + return next(action) +} + +const middleware = options => (req, res, next) => { + // ... +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const fn = b => c => d => { + return 3; +}; + +const foo = (a, b) => c => d => { + return 3; +}; + +const bar = a => b => c => a + b + c; + const mw = store => next => action => { return next(action); }; @@ -350,6 +730,16 @@ veryLongCall( `; +exports[`long-call-no-args.js 2`] = ` +veryLongCall(VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_LONG_CONSTANT, () => {}) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +veryLongCall( + VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_LONG_CONSTANT, + () => {} +); + +`; + exports[`long-contents.js 1`] = ` const foo = () => { expect(arg1, arg2, arg3).toEqual({message: 'test', messageType: 'SMS', status: 'Unknown', created: '11/01/2017 13:36'}); @@ -366,6 +756,102 @@ const foo = () => { `; +exports[`long-contents.js 2`] = ` +const foo = () => { + expect(arg1, arg2, arg3).toEqual({message: 'test', messageType: 'SMS', status: 'Unknown', created: '11/01/2017 13:36'}); +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const foo = () => { + expect(arg1, arg2, arg3).toEqual({ + message: "test", + messageType: "SMS", + status: "Unknown", + created: "11/01/2017 13:36" + }); +}; + +`; + +exports[`parens.js 1`] = ` +promise.then( + (result) => result, + (err) => err +) + +promise.then( + (result) => { f(); return result }, + (err) => { f(); return err } +) + +foo(a => b) +foo(a => { return b }) +foo(c, a => b) +foo(c, a => b, d) +foo(a => b, d) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +promise.then(result => result, err => err); + +promise.then( + result => { + f(); + return result; + }, + err => { + f(); + return err; + } +); + +foo(a => b); +foo(a => { + return b; +}); +foo(c, a => b); +foo(c, a => b, d); +foo(a => b, d); + +`; + +exports[`parens.js 2`] = ` +promise.then( + (result) => result, + (err) => err +) + +promise.then( + (result) => { f(); return result }, + (err) => { f(); return err } +) + +foo(a => b) +foo(a => { return b }) +foo(c, a => b) +foo(c, a => b, d) +foo(a => b, d) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +promise.then(result => result, err => err); + +promise.then( + result => { + f(); + return result; + }, + err => { + f(); + return err; + } +); + +foo(a => b); +foo(a => { + return b; +}); +foo(c, a => b); +foo(c, a => b, d); +foo(a => b, d); + +`; + exports[`short_body.js 1`] = ` const initializeSnapshotState = ( testFile: Path, @@ -383,9 +869,33 @@ const initializeSnapshotState = ( `; +exports[`short_body.js 2`] = ` +const initializeSnapshotState = ( + testFile: Path, + update: boolean, + testPath: string, + expand: boolean, +) => new SnapshotState(testFile, update, testPath, expand); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const initializeSnapshotState = ( + testFile: Path, + update: boolean, + testPath: string, + expand: boolean +) => new SnapshotState(testFile, update, testPath, expand); + +`; + exports[`type_params.js 1`] = ` (a) => { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (a) => {}; `; + +exports[`type_params.js 2`] = ` +(a) => { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(a) => {}; + +`; diff --git a/tests/arrows/arrow_function_expression.js b/tests/arrows/arrow_function_expression.js index 4e0071e03..ceae6d7ae 100644 --- a/tests/arrows/arrow_function_expression.js +++ b/tests/arrows/arrow_function_expression.js @@ -29,3 +29,7 @@ x => (y = z); x => (y += z); f(a => ({})) + 1; (a => ({})) || 0; +a = b => c; +a = b => { + return c +}; diff --git a/tests/arrows/currying.js b/tests/arrows/currying.js index e1a4c7e2a..1e3b36d1f 100644 --- a/tests/arrows/currying.js +++ b/tests/arrows/currying.js @@ -2,6 +2,12 @@ const fn = b => c => d => { return 3; }; +const foo = (a, b) => c => d => { + return 3; +}; + +const bar = a => b => c => a + b + c + const mw = store => next => action => { return next(action) } diff --git a/tests/arrows/jsfmt.spec.js b/tests/arrows/jsfmt.spec.js index 6a6711aef..5db62db64 100644 --- a/tests/arrows/jsfmt.spec.js +++ b/tests/arrows/jsfmt.spec.js @@ -1 +1,6 @@ -run_spec(__dirname, { parser: "babylon" }, ["typescript"]); +run_spec(__dirname, { parser: "babylon", arrowFunctionParentheses: "avoid" }, [ + "typescript" +]); +run_spec(__dirname, { parser: "babylon", arrowFunctionParentheses: "always" }, [ + "typescript" +]); diff --git a/tests/arrows/parens.js b/tests/arrows/parens.js new file mode 100644 index 000000000..e9b5f424c --- /dev/null +++ b/tests/arrows/parens.js @@ -0,0 +1,15 @@ +promise.then( + (result) => result, + (err) => err +) + +promise.then( + (result) => { f(); return result }, + (err) => { f(); return err } +) + +foo(a => b) +foo(a => { return b }) +foo(c, a => b) +foo(c, a => b, d) +foo(a => b, d) diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap index 681c3baed..35aced0cd 100644 --- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap @@ -1,5 +1,23 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`show detailed usage with --help arrow-function-parentheses (stderr) 1`] = `""`; + +exports[`show detailed usage with --help arrow-function-parentheses (stdout) 1`] = ` +"--arrow-function-parentheses + + Include parentheses around a sole arrow function parameter. + +Valid options: + + avoid Omit parens when possible. Example: \`x => x\` + always Always include parens. Example: \`(x) => x\` + +Default: avoid +" +`; + +exports[`show detailed usage with --help arrow-function-parentheses (write) 1`] = `Array []`; + exports[`show detailed usage with --help bracket-spacing (stderr) 1`] = `""`; exports[`show detailed usage with --help bracket-spacing (stdout) 1`] = ` @@ -477,6 +495,9 @@ Output options: Format options: + --arrow-function-parentheses + Include parentheses around a sole arrow function parameter. + Defaults to avoid. --no-bracket-spacing Do not print spaces between brackets. --jsx-bracket-same-line Put > on the last line instead of at a new line. Defaults to false. @@ -610,6 +631,9 @@ Output options: Format options: + --arrow-function-parentheses + Include parentheses around a sole arrow function parameter. + Defaults to avoid. --no-bracket-spacing Do not print spaces between brackets. --jsx-bracket-same-line Put > on the last line instead of at a new line. Defaults to false. From e4eb8a4065e47a50f27f2826ce480ade5c4bc38b Mon Sep 17 00:00:00 2001 From: Stephen Scott Date: Sun, 26 Nov 2017 16:27:03 -0700 Subject: [PATCH 2/9] Add implementation for arrow parens option Based on https://github.com/prettier/prettier/pull/2676 * Thread `path` and `options` through helpers so we don't need to add `needsParens` onto the AST node anymore (mutation) * Pull test call detection logic out into helper method so it can be re-used for arrow function parens * Add arrow function parens option implementation (avoid/always) * Don't break arrow function parens around (done) in test call --- src/printer.js | 124 +++++++--- .../__snapshots__/jsfmt.spec.js.snap | 8 +- tests/arrows/__snapshots__/jsfmt.spec.js.snap | 72 +++--- .../__snapshots__/jsfmt.spec.js.snap | 211 ++++++++++++++++++ tests/test_declarations/jsfmt.spec.js | 1 + tests/test_declarations/test_declarations.js | 4 + 6 files changed, 343 insertions(+), 77 deletions(-) diff --git a/src/printer.js b/src/printer.js index 4351710d3..645dd2f03 100644 --- a/src/printer.js +++ b/src/printer.js @@ -214,14 +214,6 @@ function genericPrint(path, options, printPath, args) { needsParens = path.needsParens(options); } - if (node.type) { - // HACK: ASI prevention in no-semi mode relies on knowledge of whether - // or not a paren has been inserted (see `exprNeedsASIProtection()`). - // For now, we're just passing that information by mutating the AST here, - // but it would be nice to find a cleaner way to do this. - node.needsParens = needsParens; - } - const parts = []; if (needsParens) { parts.unshift("("); @@ -501,7 +493,7 @@ function genericPrintNoParens(path, options, print, args) { parts.push("async "); } - if (canPrintParamsWithoutParens(n)) { + if (shouldPrintParamsWithoutParens(path, options)) { parts.push(path.call(print, "params", 0)); } else { parts.push( @@ -855,7 +847,6 @@ function genericPrintNoParens(path, options, print, args) { case "NewExpression": case "CallExpression": { const isNew = n.type === "NewExpression"; - const unitTestRe = /^(f|x)?(it|describe|test)$/; const optional = printOptionalToken(path); if ( @@ -869,22 +860,7 @@ function genericPrintNoParens(path, options, print, args) { isTemplateOnItsOwnLine(n.arguments[0], options.originalText)) || // Keep test declarations on a single line // e.g. `it('long name', () => {` - (!isNew && - ((n.callee.type === "Identifier" && unitTestRe.test(n.callee.name)) || - (n.callee.type === "MemberExpression" && - n.callee.object.type === "Identifier" && - n.callee.property.type === "Identifier" && - unitTestRe.test(n.callee.object.name) && - (n.callee.property.name === "only" || - n.callee.property.name === "skip"))) && - n.arguments.length === 2 && - (n.arguments[0].type === "StringLiteral" || - n.arguments[0].type === "TemplateLiteral" || - (n.arguments[0].type === "Literal" && - typeof n.arguments[0].value === "string")) && - (n.arguments[1].type === "FunctionExpression" || - n.arguments[1].type === "ArrowFunctionExpression") && - n.arguments[1].params.length <= 1) + (!isNew && isTestCall(n)) ) { return concat([ isNew ? "new " : "", @@ -2873,11 +2849,9 @@ function printStatementSequence(path, options, print) { !options.semi && !isClass && !isTheOnlyJSXElementInMarkdown(options, stmtPath) && - stmtNeedsASIProtection(stmtPath) + stmtNeedsASIProtection(stmtPath, options) ) { if (stmt.comments && stmt.comments.some(comment => comment.leading)) { - // Note: stmtNeedsASIProtection requires stmtPath to already be printed - // as it reads needsParens which is mutated on the instance parts.push(print(stmtPath, { needsSemi: true })); } else { parts.push(";", stmtPrinted); @@ -3228,6 +3202,11 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { const parent = path.getParentNode(); + // don't break in specs, eg; `it("should maintain parens around done even when long", (done) => {})` + if (parent.type === "CallExpression" && isTestCall(parent)) { + return concat([typeParams, "(", join(", ", printed), ")"]); + } + const flowTypeAnnotations = [ "AnyTypeAnnotation", "NullLiteralTypeAnnotation", @@ -3282,6 +3261,19 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { ]); } +function shouldPrintParamsWithoutParens(path, options) { + if (options.arrowFunctionParentheses === "always") { + return false; + } + + if (options.arrowFunctionParentheses === "avoid") { + const node = path.getValue(); + return canPrintParamsWithoutParens(node); + } + + return false; +} + function canPrintParamsWithoutParens(node) { return ( node.params.length === 1 && @@ -4683,15 +4675,43 @@ function getLeftSide(node) { ); } -function exprNeedsASIProtection(node) { - // HACK: node.needsParens is added in `genericPrint()` for the sole purpose - // of being used here. It'd be preferable to find a cleaner way to do this. +function getLeftSidePathName(path, node) { + if (node.expressions) { + return ["expressions", 0]; + } + if (node.left) { + return ["left"]; + } + if (node.test) { + return ["test"]; + } + if (node.callee) { + return ["callee"]; + } + if (node.object) { + return ["object"]; + } + if (node.tag) { + return ["tag"]; + } + if (node.argument) { + return ["argument"]; + } + if (node.expression) { + return ["expression"]; + } + throw new Error("Unexpected node has no left side", node); +} + +function exprNeedsASIProtection(path, options) { + const node = path.getValue(); + const maybeASIProblem = - node.needsParens || + path.needsParens(options) || node.type === "ParenthesizedExpression" || node.type === "TypeCastExpression" || (node.type === "ArrowFunctionExpression" && - !canPrintParamsWithoutParens(node)) || + !shouldPrintParamsWithoutParens(path, options)) || node.type === "ArrayExpression" || node.type === "ArrayPattern" || (node.type === "UnaryExpression" && @@ -4713,17 +4733,25 @@ function exprNeedsASIProtection(node) { return false; } - return exprNeedsASIProtection(getLeftSide(node)); + return path.call.apply( + path, + [childPath => exprNeedsASIProtection(childPath, options)].concat( + getLeftSidePathName(path, node) + ) + ); } -function stmtNeedsASIProtection(path) { +function stmtNeedsASIProtection(path, options) { const node = path.getNode(); if (node.type !== "ExpressionStatement") { return false; } - return exprNeedsASIProtection(node.expression); + return path.call( + childPath => exprNeedsASIProtection(childPath, options), + "expression" + ); } function classPropMayCauseASIProblems(path) { @@ -4992,6 +5020,28 @@ function isObjectType(n) { return n.type === "ObjectTypeAnnotation" || n.type === "TSTypeLiteral"; } +// eg; `describe("some string", (done) => {})` +function isTestCall(n) { + const unitTestRe = /^(f|x)?(it|describe|test)$/; + return ( + ((n.callee.type === "Identifier" && unitTestRe.test(n.callee.name)) || + (n.callee.type === "MemberExpression" && + n.callee.object.type === "Identifier" && + n.callee.property.type === "Identifier" && + unitTestRe.test(n.callee.object.name) && + (n.callee.property.name === "only" || + n.callee.property.name === "skip"))) && + n.arguments.length === 2 && + (n.arguments[0].type === "StringLiteral" || + n.arguments[0].type === "TemplateLiteral" || + (n.arguments[0].type === "Literal" && + typeof n.arguments[0].value === "string")) && + (n.arguments[1].type === "FunctionExpression" || + n.arguments[1].type === "ArrowFunctionExpression") && + n.arguments[1].params.length <= 1 + ); +} + function printAstToDoc(ast, options, addAlignmentSize) { addAlignmentSize = addAlignmentSize || 0; diff --git a/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap b/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap index 006da744c..92c455575 100644 --- a/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap +++ b/tests/arrow-call/__snapshots__/jsfmt.spec.js.snap @@ -234,7 +234,7 @@ const composition = (ViewComponent, ContainerComponent) => static propTypes = {}; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -const testResults = results.testResults.map(testResult => +const testResults = results.testResults.map((testResult) => formatResult(testResult, formatter, reporter) ); @@ -265,16 +265,16 @@ expect(() => ).not.toThrowError(); const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map( - response => response.data + (response) => response.data ); const b = Observable.fromPromise(axiosInstance.get(url)).map( - response => response.data + (response) => response.data ); func( veryLoooooooooooooooooooooooongName, - veryLooooooooooooooooooooooooongName => + (veryLooooooooooooooooooooooooongName) => veryLoooooooooooooooongName.something() ); diff --git a/tests/arrows/__snapshots__/jsfmt.spec.js.snap b/tests/arrows/__snapshots__/jsfmt.spec.js.snap index c4794e33f..e9786867e 100644 --- a/tests/arrows/__snapshots__/jsfmt.spec.js.snap +++ b/tests/arrows/__snapshots__/jsfmt.spec.js.snap @@ -113,7 +113,7 @@ a = b => { return c }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(a => {}).length; +((a) => {}).length; typeof (() => {}); export default (() => {})(); (() => {})()\`\`; @@ -133,20 +133,20 @@ a = () => ({}[b] && a); a = () => ({}\`\` && a); a = () => ({} = 0); a = () => ({}, a); -a => a instanceof {}; -a => ({}().b && 0); -a => ({}().c = 0); -x => ({}()()); -x => ({}()\`\`); -x => ({}().b); -a = b => c; +(a) => a instanceof {}; +(a) => ({}().b && 0); +(a) => ({}().c = 0); +(x) => ({}()()); +(x) => ({}()\`\`); +(x) => ({}().b); +a = (b) => c; a = (b?) => c; -x => (y = z); -x => (y += z); -f(a => ({})) + 1; -(a => ({})) || 0; -a = b => c; -a = b => { +(x) => (y = z); +(x) => (y += z); +f((a) => ({})) + 1; +((a) => ({})) || 0; +a = (b) => c; +a = (b) => { return c; }; @@ -421,7 +421,7 @@ fooooooooooooooooooooooooooooooooooooooooooooooooooo(action => next => dispatch(action), ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Seq(typeDef.interface.groups).forEach(group => +Seq(typeDef.interface.groups).forEach((group) => Seq(group.members).forEach((member, memberName) => markdownDoc(member.doc, { typePath: typePath.concat(memberName.slice(1)), @@ -430,7 +430,7 @@ Seq(typeDef.interface.groups).forEach(group => ) ); -const promiseFromCallback = fn => +const promiseFromCallback = (fn) => new Promise((resolve, reject) => fn((err, result) => { if (err) return reject(err); @@ -452,7 +452,7 @@ function render() { return ( + onProgress={(e) => this.setState({ progress: Math.round( 100 * e.nativeEvent.loaded / e.nativeEvent.total @@ -468,7 +468,7 @@ function render() { return ( + onProgress={(e) => this.setState({ progress: Math.round( 100 * e.nativeEvent.loaded / e.nativeEvent.total @@ -484,7 +484,7 @@ function render() { return ( + onProgress={(e) => this.setState({ progress: Math.round( 100 * e.nativeEvent.loaded / e.nativeEvent.total @@ -506,7 +506,7 @@ jest.mock( } ); -fooooooooooooooooooooooooooooooooooooooooooooooooooo(action => next => +fooooooooooooooooooooooooooooooooooooooooooooooooooo((action) => (next) => dispatch(action) ); @@ -615,17 +615,17 @@ export const bem = block => * @param {String} block - the BEM Block you'd like to select. * @returns {Function} */ -export const bem = block => +export const bem = (block) => /** * @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself. * @returns {Function} */ - element => + (element) => /** * @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified. * @returns {String} */ - modifier => + (modifier) => [ ".", css(block), @@ -700,21 +700,21 @@ const middleware = options => (req, res, next) => { // ... }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -const fn = b => c => d => { +const fn = (b) => (c) => (d) => { return 3; }; -const foo = (a, b) => c => d => { +const foo = (a, b) => (c) => (d) => { return 3; }; -const bar = a => b => c => a + b + c; +const bar = (a) => (b) => (c) => a + b + c; -const mw = store => next => action => { +const mw = (store) => (next) => (action) => { return next(action); }; -const middleware = options => (req, res, next) => { +const middleware = (options) => (req, res, next) => { // ... }; @@ -829,26 +829,26 @@ foo(c, a => b) foo(c, a => b, d) foo(a => b, d) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -promise.then(result => result, err => err); +promise.then((result) => result, (err) => err); promise.then( - result => { + (result) => { f(); return result; }, - err => { + (err) => { f(); return err; } ); -foo(a => b); -foo(a => { +foo((a) => b); +foo((a) => { return b; }); -foo(c, a => b); -foo(c, a => b, d); -foo(a => b, d); +foo(c, (a) => b); +foo(c, (a) => b, d); +foo((a) => b, d); `; diff --git a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap index 46df9e4ee..19debeed9 100644 --- a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap +++ b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap @@ -34,6 +34,10 @@ test(\`does something really long and complicated so I have to write a very long console.log("hello!"); }); +test("does something really long and complicated so I have to write a very long name for the test", (done) => { + console.log("hello!"); +}); + describe("does something really long and complicated so I have to write a very long name for the describe block", () => { it("an example test", (done) => { console.log("hello!"); @@ -123,6 +127,12 @@ test(\`does something really long and complicated so I have to write a very long console.log("hello!"); }); +test("does something really long and complicated so I have to write a very long name for the test", < + T +>(done) => { + console.log("hello!"); +}); + describe("does something really long and complicated so I have to write a very long name for the describe block", () => { it("an example test", done => { console.log("hello!"); @@ -190,3 +200,204 @@ it.only.only( ); `; + +exports[`test_declarations.js 2`] = ` +// Shouldn't break + +it("does something really long and complicated so I have to write a very long name for the test", () => { + console.log("hello!"); +}); + +it("does something really long and complicated so I have to write a very long name for the test", function() { + console.log("hello!"); +}); + +it(\`does something really long and complicated so I have to write a very long name for the test\`, function() { + console.log("hello!"); +}); + +it(\`{foo + bar} does something really long and complicated so I have to write a very long name for the test\`, function() { + console.log("hello!"); +}); + +it(\`handles + some + newlines + does something really long and complicated so I have to write a very long name for the test\`, () => { + console.log("hello!"); +}) + +test("does something really long and complicated so I have to write a very long name for the test", (done) => { + console.log("hello!"); +}); + +test(\`does something really long and complicated so I have to write a very long name for the test\`, (done) => { + console.log("hello!"); +}); + +test("does something really long and complicated so I have to write a very long name for the test", (done) => { + console.log("hello!"); +}); + +describe("does something really long and complicated so I have to write a very long name for the describe block", () => { + it("an example test", (done) => { + console.log("hello!"); + }); +}); + +describe(\`does something really long and complicated so I have to write a very long name for the describe block\`, () => { + it(\`an example test\`, (done) => { + console.log("hello!"); + }); +}); + +xdescribe("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +fdescribe("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +describe.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +describe.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +fit("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +xit("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +it.only("does something really long and complicated so I have to write a very long name for the test", () => { + console.log("hello!"); +}); + +it.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => { + console.log("hello!"); +}); + +it.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +test.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +test.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +ftest("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +xtest("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +// Should break + +it.only("does something really long and complicated so I have to write a very long name for the test", 10, () => { + console.log("hello!"); +}); + +it.only.only("does something really long and complicated so I have to write a very long name for the test", () => { + console.log("hello!"); +}); + +it.only.only("does something really long and complicated so I have to write a very long name for the test", (a, b, c) => { + console.log("hello!"); +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Shouldn't break + +it("does something really long and complicated so I have to write a very long name for the test", () => { + console.log("hello!"); +}); + +it("does something really long and complicated so I have to write a very long name for the test", function() { + console.log("hello!"); +}); + +it(\`does something really long and complicated so I have to write a very long name for the test\`, function() { + console.log("hello!"); +}); + +it(\`{foo + bar} does something really long and complicated so I have to write a very long name for the test\`, function() { + console.log("hello!"); +}); + +it(\`handles + some + newlines + does something really long and complicated so I have to write a very long name for the test\`, () => { + console.log("hello!"); +}); + +test("does something really long and complicated so I have to write a very long name for the test", (done) => { + console.log("hello!"); +}); + +test(\`does something really long and complicated so I have to write a very long name for the test\`, (done) => { + console.log("hello!"); +}); + +test("does something really long and complicated so I have to write a very long name for the test", < + T +>(done) => { + console.log("hello!"); +}); + +describe("does something really long and complicated so I have to write a very long name for the describe block", () => { + it("an example test", (done) => { + console.log("hello!"); + }); +}); + +describe(\`does something really long and complicated so I have to write a very long name for the describe block\`, () => { + it(\`an example test\`, (done) => { + console.log("hello!"); + }); +}); + +xdescribe("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +fdescribe("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +describe.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +describe.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +fit("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +xit("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +it.only("does something really long and complicated so I have to write a very long name for the test", () => { + console.log("hello!"); +}); + +it.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => { + console.log("hello!"); +}); + +it.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +test.only(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +test.skip(\`does something really long and complicated so I have to write a very long name for the test\`, () => {}); + +ftest("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +xtest("does something really long and complicated so I have to write a very long name for the describe block", () => {}); + +// Should break + +it.only( + "does something really long and complicated so I have to write a very long name for the test", + 10, + () => { + console.log("hello!"); + } +); + +it.only.only( + "does something really long and complicated so I have to write a very long name for the test", + () => { + console.log("hello!"); + } +); + +it.only.only( + "does something really long and complicated so I have to write a very long name for the test", + (a, b, c) => { + console.log("hello!"); + } +); + +`; diff --git a/tests/test_declarations/jsfmt.spec.js b/tests/test_declarations/jsfmt.spec.js index 7580dfab0..e34fd7e40 100644 --- a/tests/test_declarations/jsfmt.spec.js +++ b/tests/test_declarations/jsfmt.spec.js @@ -1 +1,2 @@ run_spec(__dirname, null, ["typescript"]); +run_spec(__dirname, { arrowFunctionParentheses: "always" }, ["typescript"]); diff --git a/tests/test_declarations/test_declarations.js b/tests/test_declarations/test_declarations.js index 165f40453..df3253b10 100644 --- a/tests/test_declarations/test_declarations.js +++ b/tests/test_declarations/test_declarations.js @@ -31,6 +31,10 @@ test(`does something really long and complicated so I have to write a very long console.log("hello!"); }); +test("does something really long and complicated so I have to write a very long name for the test", (done) => { + console.log("hello!"); +}); + describe("does something really long and complicated so I have to write a very long name for the describe block", () => { it("an example test", (done) => { console.log("hello!"); From a6c12ca7a97419557b14c3bbe3bc9e23abfdea52 Mon Sep 17 00:00:00 2001 From: Stephen Scott Date: Sun, 26 Nov 2017 16:40:11 -0700 Subject: [PATCH 3/9] Inline type parameters in test callback --- src/printer.js | 8 ++++++++ tests/test_declarations/__snapshots__/jsfmt.spec.js.snap | 8 ++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/printer.js b/src/printer.js index 645dd2f03..1a95b3fc2 100644 --- a/src/printer.js +++ b/src/printer.js @@ -3519,7 +3519,15 @@ function printTypeParameters(path, options, print, paramsKey) { return path.call(print, paramsKey); } + const grandparent = path.getNode(2); + + const isParameterInTestCall = + grandparent != null && + grandparent.type === "CallExpression" && + isTestCall(grandparent); + const shouldInline = + isParameterInTestCall || n[paramsKey].length === 0 || (n[paramsKey].length === 1 && (shouldHugType(n[paramsKey][0]) || diff --git a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap index 19debeed9..fc01c9636 100644 --- a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap +++ b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap @@ -127,9 +127,7 @@ test(\`does something really long and complicated so I have to write a very long console.log("hello!"); }); -test("does something really long and complicated so I have to write a very long name for the test", < - T ->(done) => { +test("does something really long and complicated so I have to write a very long name for the test", (done) => { console.log("hello!"); }); @@ -328,9 +326,7 @@ test(\`does something really long and complicated so I have to write a very long console.log("hello!"); }); -test("does something really long and complicated so I have to write a very long name for the test", < - T ->(done) => { +test("does something really long and complicated so I have to write a very long name for the test", (done) => { console.log("hello!"); }); From 6abdd2c6b77d46d9b645d93dd85b95847c26933d Mon Sep 17 00:00:00 2001 From: Suchipi Izumi Date: Mon, 27 Nov 2017 21:52:49 -0700 Subject: [PATCH 4/9] PR feedback --- docs/options.md | 8 ++++---- src/cli-constant.js | 2 +- src/options.js | 2 +- src/printer.js | 5 +++-- tests/arrow-call/jsfmt.spec.js | 2 +- tests/arrows/jsfmt.spec.js | 4 ++-- tests/test_declarations/jsfmt.spec.js | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/options.md b/docs/options.md index b3d83cfd4..3f6ca94b8 100644 --- a/docs/options.md +++ b/docs/options.md @@ -96,7 +96,7 @@ Put the `>` of a multi-line JSX element at the end of the last line instead of b | ------- | ------------------------- | ---------------------------- | | `false` | `--jsx-bracket-same-line` | `jsxBracketSameLine: ` | -# Arrow Function Parentheses +## Arrow Function Parentheses Include parentheses around a sole arrow function parameter. @@ -105,9 +105,9 @@ Valid options: * `"avoid"` - Omit parens when possible. Example: `x => x` * `"always"` - Always include parens. Example: `(x) => x` -| Default | CLI Override | API Override | -| --------- | --------------------------------------------------------- | ------------------------------------------------------- | -| `"avoid"` | --arrow-function-parens | arrowFunctionParentheses: "" | +| Default | CLI Override | API Override | +| --------- | ----------------------------------------------- | ----------------------------------------------- | +| `"avoid"` | --arrow-parens | arrowParens: "" | ## Range diff --git a/src/cli-constant.js b/src/cli-constant.js index 376c718b9..018540694 100644 --- a/src/cli-constant.js +++ b/src/cli-constant.js @@ -77,7 +77,7 @@ const categoryOrder = [ * Note: The options below are sorted alphabetically. */ const detailedOptions = normalizeDetailedOptions({ - "arrow-function-parentheses": { + "arrow-parens": { type: "choice", category: CATEGORY_FORMAT, forwardToApi: true, diff --git a/src/options.js b/src/options.js index 87ba34028..f0d963157 100644 --- a/src/options.js +++ b/src/options.js @@ -22,7 +22,7 @@ const defaults = { requirePragma: false, semi: true, proseWrap: true, - arrowFunctionParentheses: "avoid" + arrowParens: "avoid" }; const exampleConfig = Object.assign({}, defaults, { diff --git a/src/printer.js b/src/printer.js index 1a95b3fc2..3ac29dfaa 100644 --- a/src/printer.js +++ b/src/printer.js @@ -3262,15 +3262,16 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { } function shouldPrintParamsWithoutParens(path, options) { - if (options.arrowFunctionParentheses === "always") { + if (options.arrowParens === "always") { return false; } - if (options.arrowFunctionParentheses === "avoid") { + if (options.arrowParens === "avoid") { const node = path.getValue(); return canPrintParamsWithoutParens(node); } + // Fallback default; should be unreachable return false; } diff --git a/tests/arrow-call/jsfmt.spec.js b/tests/arrow-call/jsfmt.spec.js index db45d9868..d2d553f69 100644 --- a/tests/arrow-call/jsfmt.spec.js +++ b/tests/arrow-call/jsfmt.spec.js @@ -1,3 +1,3 @@ run_spec(__dirname, null, ["typescript"]); run_spec(__dirname, { trailingComma: "all" }, ["typescript"]); -run_spec(__dirname, { arrowFunctionParentheses: "always" }, ["typescript"]); +run_spec(__dirname, { arrowParens: "always" }, ["typescript"]); diff --git a/tests/arrows/jsfmt.spec.js b/tests/arrows/jsfmt.spec.js index 5db62db64..460cdeae4 100644 --- a/tests/arrows/jsfmt.spec.js +++ b/tests/arrows/jsfmt.spec.js @@ -1,6 +1,6 @@ -run_spec(__dirname, { parser: "babylon", arrowFunctionParentheses: "avoid" }, [ +run_spec(__dirname, { parser: "babylon", arrowParens: "avoid" }, [ "typescript" ]); -run_spec(__dirname, { parser: "babylon", arrowFunctionParentheses: "always" }, [ +run_spec(__dirname, { parser: "babylon", arrowParens: "always" }, [ "typescript" ]); diff --git a/tests/test_declarations/jsfmt.spec.js b/tests/test_declarations/jsfmt.spec.js index e34fd7e40..d5c0967c1 100644 --- a/tests/test_declarations/jsfmt.spec.js +++ b/tests/test_declarations/jsfmt.spec.js @@ -1,2 +1,2 @@ run_spec(__dirname, null, ["typescript"]); -run_spec(__dirname, { arrowFunctionParentheses: "always" }, ["typescript"]); +run_spec(__dirname, { arrowParens: "always" }, ["typescript"]); From 41a9ababc3b4fdf6b95648078e0f0f2c08b293c9 Mon Sep 17 00:00:00 2001 From: Suchipi Izumi Date: Mon, 27 Nov 2017 22:23:32 -0700 Subject: [PATCH 5/9] Add updated snapshot Whoops, forgot this --- .../__tests__/__snapshots__/early-exit.js.snap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap index 35aced0cd..3eafa6651 100644 --- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`show detailed usage with --help arrow-function-parentheses (stderr) 1`] = `""`; +exports[`show detailed usage with --help arrow-parens (stderr) 1`] = `""`; -exports[`show detailed usage with --help arrow-function-parentheses (stdout) 1`] = ` -"--arrow-function-parentheses +exports[`show detailed usage with --help arrow-parens (stdout) 1`] = ` +"--arrow-parens Include parentheses around a sole arrow function parameter. @@ -16,7 +16,7 @@ Default: avoid " `; -exports[`show detailed usage with --help arrow-function-parentheses (write) 1`] = `Array []`; +exports[`show detailed usage with --help arrow-parens (write) 1`] = `Array []`; exports[`show detailed usage with --help bracket-spacing (stderr) 1`] = `""`; @@ -495,7 +495,7 @@ Output options: Format options: - --arrow-function-parentheses + --arrow-parens Include parentheses around a sole arrow function parameter. Defaults to avoid. --no-bracket-spacing Do not print spaces between brackets. @@ -631,7 +631,7 @@ Output options: Format options: - --arrow-function-parentheses + --arrow-parens Include parentheses around a sole arrow function parameter. Defaults to avoid. --no-bracket-spacing Do not print spaces between brackets. From ac3f74e7a3697d4bc85de47b514f7925c2c99b22 Mon Sep 17 00:00:00 2001 From: Ika Date: Wed, 29 Nov 2017 00:20:26 +0800 Subject: [PATCH 6/9] docs(options): add available version for `arrow-parens` (#3339) --- docs/options.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/options.md b/docs/options.md index 3f6ca94b8..c4da1398c 100644 --- a/docs/options.md +++ b/docs/options.md @@ -98,6 +98,8 @@ Put the `>` of a multi-line JSX element at the end of the last line instead of b ## Arrow Function Parentheses +_available in v1.9.0+_ + Include parentheses around a sole arrow function parameter. Valid options: From e04f22975de10024ad9d98fc40b12c130b1b79f7 Mon Sep 17 00:00:00 2001 From: Lucas Azzola Date: Wed, 29 Nov 2017 17:45:53 +1100 Subject: [PATCH 7/9] Change "preview" to "pr" --- scripts/build/build-docs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/build-docs.js b/scripts/build/build-docs.js index 7db557996..f1ed25e07 100644 --- a/scripts/build/build-docs.js +++ b/scripts/build/build-docs.js @@ -28,7 +28,7 @@ const prettierPath = isPullRequest ? "dist" : "node_modules/prettier/"; if (isPullRequest) { const pkg = require("../../package.json"); - pkg.version = `preview-${process.env.REVIEW_ID}`; + pkg.version = `pr-${process.env.REVIEW_ID}`; pipe(JSON.stringify(pkg, null, 2)).to("package.json"); shell.exec("node scripts/build/build.js"); } From fbbfa525171f36632ae879010cba92af9a5fd896 Mon Sep 17 00:00:00 2001 From: Ika Date: Wed, 29 Nov 2017 19:13:38 +0800 Subject: [PATCH 8/9] fix(markdown): do not print linebreaks in heading (#3343) --- src/printer-markdown.js | 3 ++- tests/markdown_heading/__snapshots__/jsfmt.spec.js.snap | 7 +++++++ tests/markdown_heading/mixed.md | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/markdown_heading/mixed.md diff --git a/src/printer-markdown.js b/src/printer-markdown.js index 8ab137d4a..4a4912eba 100644 --- a/src/printer-markdown.js +++ b/src/printer-markdown.js @@ -40,7 +40,8 @@ const INLINE_NODE_TYPES = [ const INLINE_NODE_WRAPPER_TYPES = INLINE_NODE_TYPES.concat([ "tableCell", - "paragraph" + "paragraph", + "heading" ]); function genericPrint(path, options, print) { diff --git a/tests/markdown_heading/__snapshots__/jsfmt.spec.js.snap b/tests/markdown_heading/__snapshots__/jsfmt.spec.js.snap index 2da78763b..75fcf5d8b 100644 --- a/tests/markdown_heading/__snapshots__/jsfmt.spec.js.snap +++ b/tests/markdown_heading/__snapshots__/jsfmt.spec.js.snap @@ -18,6 +18,13 @@ exports[`long-heading.md 1`] = ` `; +exports[`mixed.md 1`] = ` +## LaraCart - Laravel Shopping Cart Package (http://laracart.lukepolo.com) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## LaraCart - Laravel Shopping Cart Package (http://laracart.lukepolo.com) + +`; + exports[`setext.md 1`] = ` h1 === diff --git a/tests/markdown_heading/mixed.md b/tests/markdown_heading/mixed.md new file mode 100644 index 000000000..1e5bb8766 --- /dev/null +++ b/tests/markdown_heading/mixed.md @@ -0,0 +1 @@ +## LaraCart - Laravel Shopping Cart Package (http://laracart.lukepolo.com) From 2032b70918eb4eaf3741397d08198394f776ef9e Mon Sep 17 00:00:00 2001 From: Lipis Date: Wed, 29 Nov 2017 17:50:02 +0100 Subject: [PATCH 9/9] Add Twitter social button (#3288) * Twitter Badges * Update README.md * Update README.md * Update Footer.js * Update README.md * Update Footer.js --- README.md | 3 +++ website/core/Footer.js | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8e65d2096..c597877f3 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,9 @@ code style: prettier + + Follow+Prettier+on+Twitter +

## Intro diff --git a/website/core/Footer.js b/website/core/Footer.js index 7bd0e9c08..609bb5c4a 100644 --- a/website/core/Footer.js +++ b/website/core/Footer.js @@ -56,13 +56,12 @@ class Footer extends React.Component { Stack Overflow Chat on Gitter - {/* - Twitter - */} + + Follow Prettier on Twitter +
More