message: Rework TSModuleDeclaration.
  This complexity feels very unnecessary. I'm disappointed that the
  TypeScript AST doesn't preserve enough information to get this right with
  fewer heuristics.
diff: @@ -2065,14 +2065,54 @@ function genericPrintNoParens(path, options, print) {
  case "TSExternalModuleReference":
  return concat(["require(", path.call(print, "expression"), ")"]);
  - case "TSModuleDeclaration":
  - parts.push(
  - n.declare ? "declare " : "",
  - "namespace ",
  - path.call(print, "id")
  + case "TSModuleDeclaration": {
  + const parent = path.getParentNode();
  +
  + if (parent.type === "TSModuleDeclaration") {
  + parts.push(".");
  + } else {
  + if (n.declare) {
  + parts.push("declare ");
  + }
  +
  + if (! n.global) {
  + const isExternal = n.id.type === "StringLiteral" ||
  + (n.id.type === "Literal" &&
  + typeof n.id.value === "string");
  +
  + if (isExternal) {
  + parts.push("module ");
  +
  + } else if (n.loc &&
  + n.loc.lines &&
  + n.id.loc) {
  + const prefix = n.loc.lines.sliceString(
  + n.loc.start,
  + n.id.loc.start
  );
  - var bodyLines = path.call(print, "body");
  + // These keywords are fundamentally ambiguous in the
  + // Babylon parser, and not reflected in the AST, so
  + // the best we can do is to match the original code,
  + // when possible.
  + if (prefix.indexOf("module") >= 0) {
  + parts.push("module ");
  + } else {
  + parts.push("namespace ");
  + }
  +
  + } else {
  + parts.push("namespace ");
  + }
  + }
  + }
  +
  + parts.push(path.call(print, "id"));
  +
  + if (n.body && n.body.type === "TSModuleDeclaration") {
  + parts.push(path.call(print, "body"));
  + } else if (n.body) {
  + const bodyLines = path.call(print, "body");
  if (bodyLines.isEmpty()) {
  parts.push(" {}");
  } else {
  @@ -2082,8 +2122,10 @@ function genericPrintNoParens(path, options, print) {
  "\n}"
  );
  }
  + }
  return concat(parts);
  + }
  case "TSModuleBlock":
  return path.call(function (bodyPath) {
  