Skip to content

Commit

Permalink
Stop printing unnecessary parens around single element arrow function…
Browse files Browse the repository at this point in the history
… param lists (e.g. `(x) => 2 * x;` becomes `x => 2 * x`)

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=235014974
  • Loading branch information
nreid260 authored and lauraharker committed Feb 21, 2019
1 parent 7c481a4 commit 7f3db38
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 27 deletions.
19 changes: 16 additions & 3 deletions src/com/google/javascript/jscomp/CodeGenerator.java
Expand Up @@ -21,6 +21,8 @@


import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.debugging.sourcemap.Util; import com.google.debugging.sourcemap.Util;
import com.google.javascript.jscomp.parsing.parser.FeatureSet;
import com.google.javascript.jscomp.parsing.parser.FeatureSet.Feature;
import com.google.javascript.rhino.JSDocInfo.Visibility; import com.google.javascript.rhino.JSDocInfo.Visibility;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token; import com.google.javascript.rhino.Token;
Expand Down Expand Up @@ -49,6 +51,7 @@ public class CodeGenerator {
private final boolean trustedStrings; private final boolean trustedStrings;
private final boolean quoteKeywordProperties; private final boolean quoteKeywordProperties;
private final boolean useOriginalName; private final boolean useOriginalName;
private final FeatureSet outputFeatureSet;
private final JSDocInfoPrinter jsDocInfoPrinter; private final JSDocInfoPrinter jsDocInfoPrinter;


private CodeGenerator(CodeConsumer consumer) { private CodeGenerator(CodeConsumer consumer) {
Expand All @@ -59,6 +62,7 @@ private CodeGenerator(CodeConsumer consumer) {
preserveTypeAnnotations = false; preserveTypeAnnotations = false;
quoteKeywordProperties = false; quoteKeywordProperties = false;
useOriginalName = false; useOriginalName = false;
this.outputFeatureSet = FeatureSet.BARE_MINIMUM;
this.jsDocInfoPrinter = new JSDocInfoPrinter(false); this.jsDocInfoPrinter = new JSDocInfoPrinter(false);
} }


Expand All @@ -71,6 +75,7 @@ protected CodeGenerator(CodeConsumer consumer, CompilerOptions options) {
this.preserveTypeAnnotations = options.preserveTypeAnnotations; this.preserveTypeAnnotations = options.preserveTypeAnnotations;
this.quoteKeywordProperties = options.shouldQuoteKeywordProperties(); this.quoteKeywordProperties = options.shouldQuoteKeywordProperties();
this.useOriginalName = options.getUseOriginalNamesInOutput(); this.useOriginalName = options.getUseOriginalNamesInOutput();
this.outputFeatureSet = options.getOutputFeatureSet();
this.jsDocInfoPrinter = new JSDocInfoPrinter(useOriginalName); this.jsDocInfoPrinter = new JSDocInfoPrinter(useOriginalName);
} }


Expand Down Expand Up @@ -297,9 +302,17 @@ protected void add(Node n, Context context) {
break; break;


case PARAM_LIST: case PARAM_LIST:
add("("); // If this is the list for a non-TypeScript arrow function with one simple name param.
addList(first); if (n.getParent().isArrowFunction()
add(")"); && n.hasOneChild()
&& first.isName()
&& !outputFeatureSet.has(Feature.TYPE_ANNOTATION)) {
add(first);
} else {
add("(");
addList(first);
add(")");
}
break; break;


case DEFAULT_VALUE: case DEFAULT_VALUE:
Expand Down
62 changes: 42 additions & 20 deletions test/com/google/javascript/jscomp/CodePrinterTest.java
Expand Up @@ -1149,7 +1149,7 @@ public void testPrettyPrinter4() {


@Test @Test
public void testPrettyPrinter_arrow() { public void testPrettyPrinter_arrow() {
assertPrettyPrint("(a)=>123;", "(a) => 123;\n"); assertPrettyPrint("(a)=>123;", "a => 123;\n");
} }


@Test @Test
Expand Down Expand Up @@ -2751,18 +2751,33 @@ public void testMemberGeneratorYield1() {
} }


@Test @Test
public void testArrowFunction() { public void testArrowFunction_zeroParams() {
assertPrintSame("()=>1"); assertPrintSame("()=>1");
assertPrint("(()=>1)", "()=>1"); assertPrint("(()=>1)", "()=>1");
assertPrintSame("()=>{}"); assertPrintSame("()=>{}");
assertPrint("a=>b", "(a)=>b");
assertPrint("(a=>b)(1)", "((a)=>b)(1)");
assertPrintSame("var z={x:(a)=>1}");
assertPrint("(a,b)=>b", "(a,b)=>b");
assertPrintSame("()=>(a,b)");
assertPrint("(()=>a),b", "()=>a,b"); assertPrint("(()=>a),b", "()=>a,b");
assertPrint("()=>(a=b)", "()=>a=b"); assertPrint("()=>(a=b)", "()=>a=b");
assertPrintSame("[1,2].forEach((x)=>y)"); }

@Test
public void testArrowFunction_oneParam() {
assertPrintSame("a=>b");
assertPrintSame("([a])=>b");
assertPrintSame("(...a)=>b");
assertPrintSame("(a=0)=>b");
assertPrintSame("(a=>b)(1)");
assertPrintSame("var z={x:a=>1}");
assertPrintSame("[1,2].forEach(x=>y)");
}

@Test
public void testArrowFunction_manyParams() {
assertPrintSame("(a,b)=>b");
}

@Test
public void testArrowFunction_bodyEdgeCases() {
assertPrintSame("()=>(a,b)");
assertPrintSame("()=>({a:1})"); assertPrintSame("()=>({a:1})");
assertPrintSame("()=>{return 1}"); assertPrintSame("()=>{return 1}");
} }
Expand Down Expand Up @@ -2793,6 +2808,8 @@ public void testAsyncGeneratorFunction() {
public void testAsyncArrowFunction() { public void testAsyncArrowFunction() {
languageMode = LanguageMode.ECMASCRIPT_NEXT; languageMode = LanguageMode.ECMASCRIPT_NEXT;
assertPrintSame("async()=>1"); assertPrintSame("async()=>1");
assertPrint("async (a) => 1", "async a=>1");

// implicit semicolon prevents async being treated as a keyword // implicit semicolon prevents async being treated as a keyword
assertPrint("f=async\n()=>1", "f=async;()=>1"); assertPrint("f=async\n()=>1", "f=async;()=>1");
} }
Expand Down Expand Up @@ -2826,36 +2843,41 @@ public void testAwaitExpression() {
assertPrintSame("pwait=async function(promise){return await promise}"); assertPrintSame("pwait=async function(promise){return await promise}");
assertPrintSame("class C{async pwait(promise){await promise}}"); assertPrintSame("class C{async pwait(promise){await promise}}");
assertPrintSame("o={async pwait(promise){await promise}}"); assertPrintSame("o={async pwait(promise){await promise}}");
assertPrintSame("pwait=async(promise)=>await promise"); assertPrintSame("pwait=async promise=>await promise");
} }


/** Regression test for b/28633247 - necessary parens dropped around arrow functions. */ /**
* Regression test for b/28633247 - necessary parens dropped around arrow functions.
*
* <p>Many of these cases use single param arrows because their PARAM_LIST parens should also be
* dropped, which can make this harder to parse for humans.
*/
@Test @Test
public void testParensAroundArrow() { public void testParensAroundArrow() {
// Parens required for non-assignment binary operator // Parens required for non-assignment binary operator
assertPrintSame("x||((_)=>true)"); assertPrint("x||((_)=>true)", "x||(_=>true)");
// Parens required for unary operator // Parens required for unary operator
assertPrintSame("void((e)=>e*5)"); assertPrint("void((e)=>e*5)", "void(e=>e*5)");
// Parens not required for comma operator // Parens not required for comma operator
assertPrint("((_) => true), ((_) => false)", "(_)=>true,(_)=>false"); assertPrint("((_) => true), ((_) => false)", "_=>true,_=>false");
// Parens not required for right side of assignment operator // Parens not required for right side of assignment operator
// NOTE: An arrow function on the left side would be a parse error. // NOTE: An arrow function on the left side would be a parse error.
assertPrint("x = ((_) => _ + 1)", "x=(_)=>_+1"); assertPrint("x = ((_) => _ + 1)", "x=_=>_+1");
// Parens required for template tag // Parens required for template tag
assertPrintSame("((_)=>\"\")`template`"); assertPrint("((_)=>\"\")`template`", "(_=>\"\")`template`");
// Parens required to reference a property // Parens required to reference a property
assertPrintSame("((a,b,c)=>a+b+c).length"); assertPrintSame("((a,b,c)=>a+b+c).length");
assertPrintSame("((a,b,c)=>a+b+c)[\"length\"]"); assertPrintSame("((a,b,c)=>a+b+c)[\"length\"]");
// Parens not required when evaluating property name. // Parens not required when evaluating property name.
// (It doesn't make much sense to do it, though.) // (It doesn't make much sense to do it, though.)
assertPrint("x[((_)=>0)]", "x[(_)=>0]"); assertPrint("x[((_)=>0)]", "x[_=>0]");
// Parens required to call the arrow function immediately // Parens required to call the arrow function immediately
assertPrintSame("((x)=>x*5)(10)"); assertPrint("((x)=>x*5)(10)", "(x=>x*5)(10)");
// Parens not required for function call arguments // Parens not required for function call arguments
assertPrint("x(((_) => true), ((_) => false))", "x((_)=>true,(_)=>false)"); assertPrint("x(((_) => true), ((_) => false))", "x(_=>true,_=>false)");
// Parens required for first operand to a conditional, but not the rest. // Parens required for first operand to a conditional, but not the rest.
assertPrintSame("((x)=>1)?a:b"); assertPrint("((x)=>1)?a:b", "(x=>1)?a:b");
assertPrint("x?((x)=>0):((x)=>1)", "x?(x)=>0:(x)=>1"); assertPrint("x?((x)=>0):((x)=>1)", "x?x=>0:x=>1");
} }


@Test @Test
Expand Down
Expand Up @@ -16,12 +16,10 @@
package com.google.javascript.refactoring.examples; package com.google.javascript.refactoring.examples;


import com.google.javascript.refactoring.Scanner; import com.google.javascript.refactoring.Scanner;

import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;



/** /**
* Test case for {@link GoogBindToArrow}. * Test case for {@link GoogBindToArrow}.
*/ */
Expand Down Expand Up @@ -128,10 +126,10 @@ public void testSimpleReturn() {


assertChanges( assertChanges(
LINE_JOINER.join( LINE_JOINER.join(
"[1,2,3].forEach(goog.bind(function(x) {", "[1,2,3].forEach(goog.bind(function(x) {", //
" return y;", " return y;",
"}, this));"), "}, this));"),
"[1,2,3].forEach((x) => y);"); "[1,2,3].forEach(x => y);");
} }


/** /**
Expand Down

0 comments on commit 7f3db38

Please sign in to comment.