message: Normalize Program/File distinction more reliably in post-parse logic.
  By the time we're attaching comments, it shouldn't matter whether the
  parser returned a Program or a File as the root AST node.
  Ironically, this makes the problem reported in and happen
  regardless of which parser is used.
diff: +"use strict";
  +
  var assert = require("assert");
  var types = require("./types");
  var n = types.namedTypes;
  @@ -14,16 +16,16 @@ var util = require("./util");
  exports.parse = function parse(source, options) {
  options = normalizeOptions(options);
  - var lines = fromString(source, options);
  + const lines = fromString(source, options);
  - var sourceWithoutTabs = lines.toString({
  + const sourceWithoutTabs = lines.toString({
  tabWidth: options.tabWidth,
  reuseWhitespace: false,
  useTabs: false
  });
  - var comments = [];
  - var program = options.parser.parse(sourceWithoutTabs, {
  + let comments = [];
  + const ast = options.parser.parse(sourceWithoutTabs, {
  jsx: true,
  loc: true,
  locations: true,
  @@ -35,17 +37,44 @@ exports.parse = function parse(source, options) {
  sourceType: util.getOption(options, "sourceType", "module")
  });
  + if (Array.isArray(ast.comments)) {
  + comments = ast.comments;
  + delete ast.comments;
  + }
  +
  + if (ast.loc) {
  // If the source was empty, some parsers give loc.{start,end}.line
  // values of 0, instead of the minimum of 1.
  - util.fixFaultyLocations(program, lines);
  -
  - program.loc = program.loc || {
  + util.fixFaultyLocations(ast, lines);
  + } else {
  + ast.loc = {
  start: lines.firstPos(),
  end: lines.lastPos()
  };
  + }
  - program.loc.lines = lines;
  - program.loc.indent = 0;
  + ast.loc.lines = lines;
  + ast.loc.indent = 0;
  +
  + let file;
  + let program;
  + if (ast.type === "Program") {
  + program = ast;
  + // In order to ensure we reprint leading and trailing program
  + // comments, wrap the original Program node with a File node. Only
  + // ESTree parsers (Acorn and Esprima) return a Program as the root AST
  + // node. Most other (Babylon-like) parsers return a File.
  + file = b.file(ast, options.sourceFileName || null);
  + file.loc = {
  + start: lines.firstPos(),
  + end: lines.lastPos(),
  + lines: lines,
  + indent: 0
  + };
  + } else if (ast.type === "File") {
  + file = ast;
  + program = file.program;
  + }
  // Expand the Program node's .loc to include all comments, since
  // typically its .loc.start and .loc.end will coincide with those of the
  @@ -55,26 +84,6 @@ exports.parse = function parse(source, options) {
  program.loc.start = trueProgramLoc.start;
  program.loc.end = trueProgramLoc.end;
  - if (program.comments) {
  - comments = program.comments;
  - delete program.comments;
  - }
  -
  - // In order to ensure we reprint leading and trailing program comments,
  - // wrap the original Program node with a File node.
  - var file = program;
  - if (file.type === "Program") {
  - var file = b.file(program, options.sourceFileName || null);
  - file.loc = {
  - lines: lines,
  - indent: 0,
  - start: lines.firstPos(),
  - end: lines.lastPos()
  - };
  - } else if (file.type === "File") {
  - program = file.program;
  - }
  -
  // Passing file.program here instead of just file means that initial
  // comments will be attached to program.body[0] instead of program.
  attachComments(
  