Repository: jlongster/prettier
Pull request #221 (2017-01-15 22:31:31)

Add flow parser experimental options
The Nuclide codebase uses features that are still proposals which require a flag to be enabled. Babylon parses them fine without any flags.

Let's enable them by default as it doesn't cost much, you either are using those features and you don't want the parser to break, or you are not and you don't care.

After this and #218, none of the nuclide files are throwing exceptions anymore! (yay!)


Patch:
diff --git a/index.js b/index.js
index 1f7fed44d..546c60ac9 100644
--- a/index.js
+++ b/index.js
@@ -28,7 +28,11 @@ function format(text, opts) {
   let ast;
 
   if (opts.useFlowParser) {
-    ast = flowParser.parse(text);
+    ast = flowParser.parse(text, {
+      esproposal_class_instance_fields: true,
+      esproposal_class_static_fields: true,
+      esproposal_export_star_as: true,
+    });
     if (ast.errors.length > 0) {
       let msg = ast.errors[(0)].message + " on line " +
         ast.errors[(0)].loc.start.line;
diff --git a/src/util.js b/src/util.js
index bc51155ef..ae727036c 100644
--- a/src/util.js
+++ b/src/util.js
@@ -41,9 +41,7 @@ function expandLoc(parentNode, childNode) {
 }
 
 util.fixFaultyLocations = function(node, text) {
-  if (node.type === "TemplateLiteral") {
-    fixTemplateLiteral(node, text);
-  } else if (node.decorators) {
+  if (node.decorators) {
     // Expand the loc of the node responsible for printing the decorators
     // (here, the decorated node) so that it includes node.decorators.
     node.decorators.forEach(function(decorator) {
@@ -79,68 +77,6 @@ util.fixFaultyLocations = function(node, text) {
   }
 };
 
-function fixTemplateLiteral(node, text) {
-  assert.strictEqual(node.type, "TemplateLiteral");
-
-  if (node.quasis.length === 0) {
-    // If there are no quasi elements, then there is nothing to fix.
-    return;
-  }
-
-  // First we need to exclude the opening ` from the loc of the first
-  // quasi element, in case the parser accidentally decided to include it.
-  var afterLeftBackTickPos = locStart(node);
-  assert.strictEqual(text.charAt(afterLeftBackTickPos), "`");
-  assert.ok(afterLeftBackTickPos < text.length);
-  var firstQuasi = node.quasis[(0)];
-  if (locStart(firstQuasi) - afterLeftBackTickPos < 0) {
-    setLocStart(firstQuasi, afterLeftBackTickPos);
-  }
-
-  // Next we need to exclude the closing ` from the loc of the last quasi
-  // element, in case the parser accidentally decided to include it.
-  var rightBackTickPos = locEnd(node);
-  assert.ok(rightBackTickPos >= 0);
-  assert.strictEqual(text.charAt(rightBackTickPos), "`");
-  var lastQuasi = node.quasis[node.quasis.length - 1];
-  if (rightBackTickPos - locEnd(lastQuasi) < 0) {
-    setLocEnd(locEnd(lastQuasi), rightBackTickPos);
-  }
-
-  // Now we need to exclude ${ and } characters from the loc's of all
-  // quasi elements, since some parsers accidentally include them.
-  node.expressions.forEach(function(expr, i) {
-    // Rewind from the start loc over any whitespace and the ${ that
-    // precedes the expression. The position of the $ should be the
-    // same as the end of the preceding quasi element, but some
-    // parsers accidentally include the ${ in the loc of the quasi
-    // element.
-    var dollarCurlyPos = skipSpaces(text, locStart(expr) - 1, true);
-    if (
-      dollarCurlyPos - 1 >= 0 && text.charAt(dollarCurlyPos - 1) === "{" &&
-        dollarCurlyPos - 2 >= 0 &&
-        text.charAt(dollarCurlyPos - 2) === "$"
-    ) {
-      var quasiBefore = node.quasis[i];
-      if (dollarCurlyPos - locEnd(quasiBefore) < 0) {
-        setLocEnd(quasiBefore, dollarCurlyPos);
-      }
-    }
-
-    // Likewise, some parsers accidentally include the } that follows
-    // the expression in the loc of the following quasi element.
-    var rightCurlyPos = skipSpaces(text, locEnd(expr));
-    if (text.charAt(rightCurlyPos) === "}") {
-      assert.ok(rightCurlyPos + 1 < text.length);
-      // Now rightCurlyPos is technically the position just after the }.
-      var quasiAfter = node.quasis[i + 1];
-      if (locStart(quasiAfter) - rightCurlyPos < 0) {
-        setLocStart(locStart(quasiAfter), rightCurlyPos);
-      }
-    }
-  });
-}
-
 util.isExportDeclaration = function(node) {
   if (node)
     switch (node.type) {


Test patch:
diff --git a/tests/template/__snapshots__/jsfmt.spec.js.snap b/tests/template/__snapshots__/jsfmt.spec.js.snap
index 55258e7bd..70c3fb59a 100644
--- a/tests/template/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/template/__snapshots__/jsfmt.spec.js.snap
@@ -1,3 +1,32 @@
+exports[`test faulty-locations.js 1`] = `
+"var o = {
+  [\`key\`]: () => {
+    // Comment
+  }
+};
+
+var x = {
+  y: () => Relay.QL\`
+    query {
+      \${foo},
+      field,
+    }
+  \`
+};
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+var o = { [\`key\`]: () => {} };
+
+var x = {
+  y: () => Relay.QL\`
+    query {
+      \${foo},
+      field,
+    }
+  \`
+};
+"
+`;
+
 exports[`test template.js 1`] = `
 "/* @flow */
 
diff --git a/tests/template/faulty-locations.js b/tests/template/faulty-locations.js
new file mode 100644
index 000000000..15a8559c0
--- /dev/null
+++ b/tests/template/faulty-locations.js
@@ -0,0 +1,14 @@
+var o = {
+  [`key`]: () => {
+    // Comment
+  }
+};
+
+var x = {
+  y: () => Relay.QL`
+    query {
+      ${foo},
+      field,
+    }
+  `
+};
diff --git a/tests_config/run_spec.js b/tests_config/run_spec.js
index 9be8940fe..78ed9ca07 100644
--- a/tests_config/run_spec.js
+++ b/tests_config/run_spec.js
@@ -76,7 +76,11 @@ function stripLocation(ast) {
 
 function parse(string) {
   const flowParser = require('flow-parser');
-  return stripLocation(flowParser.parse(string));
+  return stripLocation(flowParser.parse(string, {
+    esproposal_class_instance_fields: true,
+    esproposal_class_static_fields: true,
+    esproposal_export_star_as: true,
+  }));
 }
 
 function prettyprint(src, filename, options) {