1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822
  1. var assert = require("assert");
  2. var sourceMap = require("source-map");
  3. var printComments = require("./comments").printComments;
  4. var linesModule = require("./lines");
  5. var fromString = linesModule.fromString;
  6. var concat = linesModule.concat;
  7. var normalizeOptions = require("./options").normalize;
  8. var getReprinter = require("./patcher").getReprinter;
  9. var types = require("./types");
  10. var namedTypes = types.namedTypes;
  11. var isString = types.builtInTypes.string;
  12. var isObject = types.builtInTypes.object;
  13. var FastPath = require("./fast-path");
  14. var util = require("./util");
  15. function PrintResult(code, sourceMap) {
  16. assert.ok(this instanceof PrintResult);
  17. isString.assert(code);
  18. this.code = code;
  19. if (sourceMap) {
  20. isObject.assert(sourceMap);
  21. this.map = sourceMap;
  22. }
  23. }
  24. var PRp = PrintResult.prototype;
  25. var warnedAboutToString = false;
  26. PRp.toString = function() {
  27. if (!warnedAboutToString) {
  28. console.warn(
  29. "Deprecation warning: recast.print now returns an object with " +
  30. "a .code property. You appear to be treating the object as a " +
  31. "string, which might still work but is strongly discouraged."
  32. );
  33. warnedAboutToString = true;
  34. }
  35. return this.code;
  36. };
  37. var emptyPrintResult = new PrintResult("");
  38. function Printer(originalOptions) {
  39. assert.ok(this instanceof Printer);
  40. var explicitTabWidth = originalOptions && originalOptions.tabWidth;
  41. var options = normalizeOptions(originalOptions);
  42. assert.notStrictEqual(options, originalOptions);
  43. // It's common for client code to pass the same options into both
  44. // recast.parse and recast.print, but the Printer doesn't need (and
  45. // can be confused by) options.sourceFileName, so we null it out.
  46. options.sourceFileName = null;
  47. function printWithComments(path) {
  48. assert.ok(path instanceof FastPath);
  49. return printComments(path, print);
  50. }
  51. function print(path, includeComments) {
  52. if (includeComments)
  53. return printWithComments(path);
  54. assert.ok(path instanceof FastPath);
  55. if (!explicitTabWidth) {
  56. var oldTabWidth = options.tabWidth;
  57. var loc = path.getNode().loc;
  58. if (loc && loc.lines && loc.lines.guessTabWidth) {
  59. options.tabWidth = loc.lines.guessTabWidth();
  60. var lines = maybeReprint(path);
  61. options.tabWidth = oldTabWidth;
  62. return lines;
  63. }
  64. }
  65. return maybeReprint(path);
  66. }
  67. function maybeReprint(path) {
  68. var reprinter = getReprinter(path);
  69. if (reprinter) {
  70. // Since the print function that we pass to the reprinter will
  71. // be used to print "new" nodes, it's tempting to think we
  72. // should pass printRootGenerically instead of print, to avoid
  73. // calling maybeReprint again, but that would be a mistake
  74. // because the new nodes might not be entirely new, but merely
  75. // moved from elsewhere in the AST. The print function is the
  76. // right choice because it gives us the opportunity to reprint
  77. // such nodes using their original source.
  78. return maybeAddParens(path, reprinter(print));
  79. }
  80. return printRootGenerically(path);
  81. }
  82. // Print the root node generically, but then resume reprinting its
  83. // children non-generically.
  84. function printRootGenerically(path, includeComments) {
  85. return includeComments
  86. ? printComments(path, printRootGenerically)
  87. : genericPrint(path, options, printWithComments);
  88. }
  89. // Print the entire AST generically.
  90. function printGenerically(path) {
  91. return genericPrint(path, options, printGenerically);
  92. }
  93. this.print = function(ast) {
  94. if (!ast) {
  95. return emptyPrintResult;
  96. }
  97. var lines = print(FastPath.from(ast), true);
  98. return new PrintResult(
  99. lines.toString(options),
  100. util.composeSourceMaps(
  101. options.inputSourceMap,
  102. lines.getSourceMap(
  103. options.sourceMapName,
  104. options.sourceRoot
  105. )
  106. )
  107. );
  108. };
  109. this.printGenerically = function(ast) {
  110. if (!ast) {
  111. return emptyPrintResult;
  112. }
  113. var path = FastPath.from(ast);
  114. var oldReuseWhitespace = options.reuseWhitespace;
  115. // Do not reuse whitespace (or anything else, for that matter)
  116. // when printing generically.
  117. options.reuseWhitespace = false;
  118. // TODO Allow printing of comments?
  119. var pr = new PrintResult(printGenerically(path).toString(options));
  120. options.reuseWhitespace = oldReuseWhitespace;
  121. return pr;
  122. };
  123. }
  124. exports.Printer = Printer;
  125. function maybeAddParens(path, lines) {
  126. return path.needsParens() ? concat(["(", lines, ")"]) : lines;
  127. }
  128. function genericPrint(path, options, printPath) {
  129. assert.ok(path instanceof FastPath);
  130. var node = path.getValue();
  131. var parts = [];
  132. var needsParens = false;
  133. var linesWithoutParens =
  134. genericPrintNoParens(path, options, printPath);
  135. if (! node || linesWithoutParens.isEmpty()) {
  136. return linesWithoutParens;
  137. }
  138. if (node.decorators &&
  139. node.decorators.length > 0 &&
  140. // If the parent node is an export declaration, it will be
  141. // responsible for printing node.decorators.
  142. ! util.getParentExportDeclaration(path)) {
  143. path.each(function(decoratorPath) {
  144. parts.push(printPath(decoratorPath), "\n");
  145. }, "decorators");
  146. } else if (util.isExportDeclaration(node) &&
  147. node.declaration &&
  148. node.declaration.decorators) {
  149. // Export declarations are responsible for printing any decorators
  150. // that logically apply to node.declaration.
  151. path.each(function(decoratorPath) {
  152. parts.push(printPath(decoratorPath), "\n");
  153. }, "declaration", "decorators");
  154. } else {
  155. // Nodes with decorators can't have parentheses, so we can avoid
  156. // computing path.needsParens() except in this case.
  157. needsParens = path.needsParens();
  158. }
  159. if (needsParens) {
  160. parts.unshift("(");
  161. }
  162. parts.push(linesWithoutParens);
  163. if (needsParens) {
  164. parts.push(")");
  165. }
  166. return concat(parts);
  167. }
  168. function genericPrintNoParens(path, options, print) {
  169. var n = path.getValue();
  170. if (!n) {
  171. return fromString("");
  172. }
  173. if (typeof n === "string") {
  174. return fromString(n, options);
  175. }
  176. namedTypes.Printable.assert(n);
  177. switch (n.type) {
  178. case "File":
  179. return path.call(print, "program");
  180. case "Program":
  181. return path.call(function(bodyPath) {
  182. return printStatementSequence(bodyPath, options, print);
  183. }, "body");
  184. case "Noop": // Babel extension.
  185. case "EmptyStatement":
  186. return fromString("");
  187. case "ExpressionStatement":
  188. return concat([path.call(print, "expression"), ";"]);
  189. case "ParenthesizedExpression": // Babel extension.
  190. return concat(["(", path.call(print, "expression"), ")"]);
  191. case "BinaryExpression":
  192. case "LogicalExpression":
  193. case "AssignmentExpression":
  194. return fromString(" ").join([
  195. path.call(print, "left"),
  196. n.operator,
  197. path.call(print, "right")
  198. ]);
  199. case "AssignmentPattern":
  200. return concat([
  201. path.call(print, "left"),
  202. "=",
  203. path.call(print, "right")
  204. ]);
  205. case "MemberExpression":
  206. var parts = [path.call(print, "object")];
  207. var property = path.call(print, "property");
  208. if (n.computed) {
  209. parts.push("[", property, "]");
  210. } else {
  211. parts.push(".", property);
  212. }
  213. return concat(parts);
  214. case "MetaProperty":
  215. return concat([
  216. path.call(print, "meta"),
  217. ".",
  218. path.call(print, "property")
  219. ]);
  220. case "BindExpression":
  221. var parts = [];
  222. if (n.object) {
  223. parts.push(path.call(print, "object"));
  224. }
  225. parts.push("::", path.call(print, "callee"));
  226. return concat(parts);
  227. case "Path":
  228. return fromString(".").join(n.body);
  229. case "Identifier":
  230. return concat([
  231. fromString(n.name, options),
  232. path.call(print, "typeAnnotation")
  233. ]);
  234. case "SpreadElement":
  235. case "SpreadElementPattern":
  236. case "SpreadProperty":
  237. case "SpreadPropertyPattern":
  238. case "RestElement":
  239. return concat(["...", path.call(print, "argument")]);
  240. case "FunctionDeclaration":
  241. case "FunctionExpression":
  242. var parts = [];
  243. if (n.async)
  244. parts.push("async ");
  245. parts.push("function");
  246. if (n.generator)
  247. parts.push("*");
  248. if (n.id) {
  249. parts.push(
  250. " ",
  251. path.call(print, "id"),
  252. path.call(print, "typeParameters")
  253. );
  254. }
  255. parts.push(
  256. "(",
  257. printFunctionParams(path, options, print),
  258. ")",
  259. path.call(print, "returnType"),
  260. " ",
  261. path.call(print, "body")
  262. );
  263. return concat(parts);
  264. case "ArrowFunctionExpression":
  265. var parts = [];
  266. if (n.async)
  267. parts.push("async ");
  268. if (
  269. n.params.length === 1 &&
  270. !n.rest &&
  271. n.params[0].type === 'Identifier'
  272. ) {
  273. parts.push(path.call(print, "params", 0));
  274. } else {
  275. parts.push(
  276. "(",
  277. printFunctionParams(path, options, print),
  278. ")"
  279. );
  280. }
  281. parts.push(" => ", path.call(print, "body"));
  282. return concat(parts);
  283. case "MethodDefinition":
  284. var parts = [];
  285. if (n.static) {
  286. parts.push("static ");
  287. }
  288. parts.push(printMethod(path, options, print));
  289. return concat(parts);
  290. case "YieldExpression":
  291. var parts = ["yield"];
  292. if (n.delegate)
  293. parts.push("*");
  294. if (n.argument)
  295. parts.push(" ", path.call(print, "argument"));
  296. return concat(parts);
  297. case "AwaitExpression":
  298. var parts = ["await"];
  299. if (n.all)
  300. parts.push("*");
  301. if (n.argument)
  302. parts.push(" ", path.call(print, "argument"));
  303. return concat(parts);
  304. case "ModuleDeclaration":
  305. var parts = ["module", path.call(print, "id")];
  306. if (n.source) {
  307. assert.ok(!n.body);
  308. parts.push("from", path.call(print, "source"));
  309. } else {
  310. parts.push(path.call(print, "body"));
  311. }
  312. return fromString(" ").join(parts);
  313. case "ImportSpecifier":
  314. var parts = [];
  315. if (n.imported) {
  316. parts.push(path.call(print, "imported"));
  317. if (n.local &&
  318. n.local.name !== n.imported.name) {
  319. parts.push(" as ", path.call(print, "local"));
  320. }
  321. } else if (n.id) {
  322. parts.push(path.call(print, "id"));
  323. if (n.name) {
  324. parts.push(" as ", path.call(print, "name"));
  325. }
  326. }
  327. return concat(parts);
  328. case "ExportSpecifier":
  329. var parts = [];
  330. if (n.local) {
  331. parts.push(path.call(print, "local"));
  332. if (n.exported &&
  333. n.exported.name !== n.local.name) {
  334. parts.push(" as ", path.call(print, "exported"));
  335. }
  336. } else if (n.id) {
  337. parts.push(path.call(print, "id"));
  338. if (n.name) {
  339. parts.push(" as ", path.call(print, "name"));
  340. }
  341. }
  342. return concat(parts);
  343. case "ExportBatchSpecifier":
  344. return fromString("*");
  345. case "ImportNamespaceSpecifier":
  346. var parts = ["* as "];
  347. if (n.local) {
  348. parts.push(path.call(print, "local"));
  349. } else if (n.id) {
  350. parts.push(path.call(print, "id"));
  351. }
  352. return concat(parts);
  353. case "ImportDefaultSpecifier":
  354. if (n.local) {
  355. return path.call(print, "local");
  356. }
  357. return path.call(print, "id");
  358. case "ExportDeclaration":
  359. case "ExportDefaultDeclaration":
  360. case "ExportNamedDeclaration":
  361. return printExportDeclaration(path, options, print);
  362. case "ExportAllDeclaration":
  363. var parts = ["export *"];
  364. if (n.exported) {
  365. parts.push(" as ", path.call(print, "exported"));
  366. }
  367. parts.push(
  368. " from ",
  369. path.call(print, "source")
  370. );
  371. return concat(parts);
  372. case "ExportNamespaceSpecifier":
  373. return concat(["* as ", path.call(print, "exported")]);
  374. case "ExportDefaultSpecifier":
  375. return path.call(print, "exported");
  376. case "ImportDeclaration":
  377. var parts = ["import "];
  378. if (n.importKind && n.importKind !== "value") {
  379. parts.push(n.importKind + " ");
  380. }
  381. if (n.specifiers &&
  382. n.specifiers.length > 0) {
  383. var foundImportSpecifier = false;
  384. path.each(function(specifierPath) {
  385. var i = specifierPath.getName();
  386. if (i > 0) {
  387. parts.push(", ");
  388. }
  389. var value = specifierPath.getValue();
  390. if (namedTypes.ImportDefaultSpecifier.check(value) ||
  391. namedTypes.ImportNamespaceSpecifier.check(value)) {
  392. assert.strictEqual(foundImportSpecifier, false);
  393. } else {
  394. namedTypes.ImportSpecifier.assert(value);
  395. if (!foundImportSpecifier) {
  396. foundImportSpecifier = true;
  397. parts.push("{");
  398. }
  399. }
  400. parts.push(print(specifierPath));
  401. }, "specifiers");
  402. if (foundImportSpecifier) {
  403. parts.push("}");
  404. }
  405. parts.push(" from ");
  406. }
  407. parts.push(path.call(print, "source"), ";");
  408. return concat(parts);
  409. case "BlockStatement":
  410. var naked = path.call(function(bodyPath) {
  411. return printStatementSequence(bodyPath, options, print);
  412. }, "body");
  413. if (naked.isEmpty()) {
  414. return fromString("{}");
  415. }
  416. return concat([
  417. "{\n",
  418. naked.indent(options.tabWidth),
  419. "\n}"
  420. ]);
  421. case "ReturnStatement":
  422. var parts = ["return"];
  423. if (n.argument) {
  424. var argLines = path.call(print, "argument");
  425. if (argLines.length > 1 &&
  426. (namedTypes.XJSElement &&
  427. namedTypes.XJSElement.check(n.argument) ||
  428. namedTypes.JSXElement &&
  429. namedTypes.JSXElement.check(n.argument))) {
  430. parts.push(
  431. " (\n",
  432. argLines.indent(options.tabWidth),
  433. "\n)"
  434. );
  435. } else {
  436. parts.push(" ", argLines);
  437. }
  438. }
  439. parts.push(";");
  440. return concat(parts);
  441. case "CallExpression":
  442. return concat([
  443. path.call(print, "callee"),
  444. printArgumentsList(path, options, print)
  445. ]);
  446. case "ObjectExpression":
  447. case "ObjectPattern":
  448. case "ObjectTypeAnnotation":
  449. var allowBreak = false;
  450. var isTypeAnnotation = n.type === "ObjectTypeAnnotation";
  451. var separator = isTypeAnnotation ? ';' : ',';
  452. var fields = [];
  453. if (isTypeAnnotation) {
  454. fields.push("indexers", "callProperties");
  455. }
  456. fields.push("properties");
  457. var len = 0;
  458. fields.forEach(function(field) {
  459. len += n[field].length;
  460. });
  461. var oneLine = (isTypeAnnotation && len === 1) || len === 0;
  462. var parts = [oneLine ? "{" : "{\n"];
  463. var i = 0;
  464. fields.forEach(function(field) {
  465. path.each(function(childPath) {
  466. var lines = print(childPath);
  467. if (!oneLine) {
  468. lines = lines.indent(options.tabWidth);
  469. }
  470. var multiLine = !isTypeAnnotation && lines.length > 1;
  471. if (multiLine && allowBreak) {
  472. // Similar to the logic for BlockStatement.
  473. parts.push("\n");
  474. }
  475. parts.push(lines);
  476. if (i < len - 1) {
  477. // Add an extra line break if the previous object property
  478. // had a multi-line value.
  479. parts.push(separator + (multiLine ? "\n\n" : "\n"));
  480. allowBreak = !multiLine;
  481. } else if (len !== 1 && isTypeAnnotation) {
  482. parts.push(separator);
  483. } else if (options.trailingComma) {
  484. parts.push(separator);
  485. }
  486. i++;
  487. }, field);
  488. });
  489. parts.push(oneLine ? "}" : "\n}");
  490. return concat(parts);
  491. case "PropertyPattern":
  492. return concat([
  493. path.call(print, "key"),
  494. ": ",
  495. path.call(print, "pattern")
  496. ]);
  497. case "Property": // Non-standard AST node type.
  498. if (n.method || n.kind === "get" || n.kind === "set") {
  499. return printMethod(path, options, print);
  500. }
  501. var parts = [];
  502. var key = path.call(print, "key");
  503. if (n.computed) {
  504. parts.push("[", key, "]");
  505. } else {
  506. parts.push(key);
  507. }
  508. if (! n.shorthand) {
  509. parts.push(": ", path.call(print, "value"));
  510. }
  511. return concat(parts);
  512. case "Decorator":
  513. return concat(["@", path.call(print, "expression")]);
  514. case "ArrayExpression":
  515. case "ArrayPattern":
  516. var elems = n.elements,
  517. len = elems.length;
  518. var printed = path.map(print, "elements");
  519. var joined = fromString(", ").join(printed);
  520. var oneLine = joined.getLineLength(1) <= options.wrapColumn;
  521. var parts = [oneLine ? "[" : "[\n"];
  522. path.each(function(elemPath) {
  523. var i = elemPath.getName();
  524. var elem = elemPath.getValue();
  525. if (!elem) {
  526. // If the array expression ends with a hole, that hole
  527. // will be ignored by the interpreter, but if it ends with
  528. // two (or more) holes, we need to write out two (or more)
  529. // commas so that the resulting code is interpreted with
  530. // both (all) of the holes.
  531. parts.push(",");
  532. } else {
  533. var lines = printed[i];
  534. if (oneLine) {
  535. if (i > 0)
  536. parts.push(" ");
  537. } else {
  538. lines = lines.indent(options.tabWidth);
  539. }
  540. parts.push(lines);
  541. if (i < len - 1 || (!oneLine && options.trailingComma))
  542. parts.push(",");
  543. if (!oneLine)
  544. parts.push("\n");
  545. }
  546. }, "elements");
  547. parts.push("]");
  548. return concat(parts);
  549. case "SequenceExpression":
  550. return fromString(", ").join(path.map(print, "expressions"));
  551. case "ThisExpression":
  552. return fromString("this");
  553. case "Super":
  554. return fromString("super");
  555. case "Literal":
  556. if (typeof n.value !== "string")
  557. return fromString(n.value, options);
  558. return fromString(nodeStr(n.value, options), options);
  559. case "ModuleSpecifier":
  560. if (n.local) {
  561. throw new Error(
  562. "The ESTree ModuleSpecifier type should be abstract"
  563. );
  564. }
  565. // The Esprima ModuleSpecifier type is just a string-valued
  566. // Literal identifying the imported-from module.
  567. return fromString(nodeStr(n.value, options), options);
  568. case "UnaryExpression":
  569. var parts = [n.operator];
  570. if (/[a-z]$/.test(n.operator))
  571. parts.push(" ");
  572. parts.push(path.call(print, "argument"));
  573. return concat(parts);
  574. case "UpdateExpression":
  575. var parts = [path.call(print, "argument"), n.operator];
  576. if (n.prefix)
  577. parts.reverse();
  578. return concat(parts);
  579. case "ConditionalExpression":
  580. return concat([
  581. "(", path.call(print, "test"),
  582. " ? ", path.call(print, "consequent"),
  583. " : ", path.call(print, "alternate"), ")"
  584. ]);
  585. case "NewExpression":
  586. var parts = ["new ", path.call(print, "callee")];
  587. var args = n.arguments;
  588. if (args) {
  589. parts.push(printArgumentsList(path, options, print));
  590. }
  591. return concat(parts);
  592. case "VariableDeclaration":
  593. var parts = [n.kind, " "];
  594. var maxLen = 0;
  595. var printed = path.map(function(childPath) {
  596. var lines = print(childPath);
  597. maxLen = Math.max(lines.length, maxLen);
  598. return lines;
  599. }, "declarations");
  600. if (maxLen === 1) {
  601. parts.push(fromString(", ").join(printed));
  602. } else if (printed.length > 1 ) {
  603. parts.push(
  604. fromString(",\n").join(printed)
  605. .indentTail(n.kind.length + 1)
  606. );
  607. } else {
  608. parts.push(printed[0]);
  609. }
  610. // We generally want to terminate all variable declarations with a
  611. // semicolon, except when they are children of for loops.
  612. var parentNode = path.getParentNode();
  613. if (!namedTypes.ForStatement.check(parentNode) &&
  614. !namedTypes.ForInStatement.check(parentNode) &&
  615. !(namedTypes.ForOfStatement &&
  616. namedTypes.ForOfStatement.check(parentNode))) {
  617. parts.push(";");
  618. }
  619. return concat(parts);
  620. case "VariableDeclarator":
  621. return n.init ? fromString(" = ").join([
  622. path.call(print, "id"),
  623. path.call(print, "init")
  624. ]) : path.call(print, "id");
  625. case "WithStatement":
  626. return concat([
  627. "with (",
  628. path.call(print, "object"),
  629. ") ",
  630. path.call(print, "body")
  631. ]);
  632. case "IfStatement":
  633. var con = adjustClause(path.call(print, "consequent"), options),
  634. parts = ["if (", path.call(print, "test"), ")", con];
  635. if (n.alternate)
  636. parts.push(
  637. endsWithBrace(con) ? " else" : "\nelse",
  638. adjustClause(path.call(print, "alternate"), options));
  639. return concat(parts);
  640. case "ForStatement":
  641. // TODO Get the for (;;) case right.
  642. var init = path.call(print, "init"),
  643. sep = init.length > 1 ? ";\n" : "; ",
  644. forParen = "for (",
  645. indented = fromString(sep).join([
  646. init,
  647. path.call(print, "test"),
  648. path.call(print, "update")
  649. ]).indentTail(forParen.length),
  650. head = concat([forParen, indented, ")"]),
  651. clause = adjustClause(path.call(print, "body"), options),
  652. parts = [head];
  653. if (head.length > 1) {
  654. parts.push("\n");
  655. clause = clause.trimLeft();
  656. }
  657. parts.push(clause);
  658. return concat(parts);
  659. case "WhileStatement":
  660. return concat([
  661. "while (",
  662. path.call(print, "test"),
  663. ")",
  664. adjustClause(path.call(print, "body"), options)
  665. ]);
  666. case "ForInStatement":
  667. // Note: esprima can't actually parse "for each (".
  668. return concat([
  669. n.each ? "for each (" : "for (",
  670. path.call(print, "left"),
  671. " in ",
  672. path.call(print, "right"),
  673. ")",
  674. adjustClause(path.call(print, "body"), options)
  675. ]);
  676. case "ForOfStatement":
  677. return concat([
  678. "for (",
  679. path.call(print, "left"),
  680. " of ",
  681. path.call(print, "right"),
  682. ")",
  683. adjustClause(path.call(print, "body"), options)
  684. ]);
  685. case "DoWhileStatement":
  686. var doBody = concat([
  687. "do",
  688. adjustClause(path.call(print, "body"), options)
  689. ]), parts = [doBody];
  690. if (endsWithBrace(doBody))
  691. parts.push(" while");
  692. else
  693. parts.push("\nwhile");
  694. parts.push(" (", path.call(print, "test"), ");");
  695. return concat(parts);
  696. case "DoExpression":
  697. var statements = path.call(function(bodyPath) {
  698. return printStatementSequence(bodyPath, options, print);
  699. }, "body");
  700. return concat([
  701. "do {\n",
  702. statements.indent(options.tabWidth),
  703. "\n}"
  704. ]);
  705. case "BreakStatement":
  706. var parts = ["break"];
  707. if (n.label)
  708. parts.push(" ", path.call(print, "label"));
  709. parts.push(";");
  710. return concat(parts);
  711. case "ContinueStatement":
  712. var parts = ["continue"];
  713. if (n.label)
  714. parts.push(" ", path.call(print, "label"));
  715. parts.push(";");
  716. return concat(parts);
  717. case "LabeledStatement":
  718. return concat([
  719. path.call(print, "label"),
  720. ":\n",
  721. path.call(print, "body")
  722. ]);
  723. case "TryStatement":
  724. var parts = [
  725. "try ",
  726. path.call(print, "block")
  727. ];
  728. if (n.handler) {
  729. parts.push(" ", path.call(print, "handler"));
  730. } else if (n.handlers) {
  731. path.each(function(handlerPath) {
  732. parts.push(" ", print(handlerPath));
  733. }, "handlers");
  734. }
  735. if (n.finalizer) {
  736. parts.push(" finally ", path.call(print, "finalizer"));
  737. }
  738. return concat(parts);
  739. case "CatchClause":
  740. var parts = ["catch (", path.call(print, "param")];
  741. if (n.guard)
  742. // Note: esprima does not recognize conditional catch clauses.
  743. parts.push(" if ", path.call(print, "guard"));
  744. parts.push(") ", path.call(print, "body"));
  745. return concat(parts);
  746. case "ThrowStatement":
  747. return concat(["throw ", path.call(print, "argument"), ";"]);
  748. case "SwitchStatement":
  749. return concat([
  750. "switch (",
  751. path.call(print, "discriminant"),
  752. ") {\n",
  753. fromString("\n").join(path.map(print, "cases")),
  754. "\n}"
  755. ]);
  756. // Note: ignoring n.lexical because it has no printing consequences.
  757. case "SwitchCase":
  758. var parts = [];
  759. if (n.test)
  760. parts.push("case ", path.call(print, "test"), ":");
  761. else
  762. parts.push("default:");
  763. if (n.consequent.length > 0) {
  764. parts.push("\n", path.call(function(consequentPath) {
  765. return printStatementSequence(consequentPath, options, print);
  766. }, "consequent").indent(options.tabWidth));
  767. }
  768. return concat(parts);
  769. case "DebuggerStatement":
  770. return fromString("debugger;");
  771. // JSX extensions below.
  772. case "XJSAttribute":
  773. case "JSXAttribute":
  774. var parts = [path.call(print, "name")];
  775. if (n.value)
  776. parts.push("=", path.call(print, "value"));
  777. return concat(parts);
  778. case "XJSIdentifier":
  779. case "JSXIdentifier":
  780. return fromString(n.name, options);
  781. case "XJSNamespacedName":
  782. case "JSXNamespacedName":
  783. return fromString(":").join([
  784. path.call(print, "namespace"),
  785. path.call(print, "name")
  786. ]);
  787. case "XJSMemberExpression":
  788. case "JSXMemberExpression":
  789. return fromString(".").join([
  790. path.call(print, "object"),
  791. path.call(print, "property")
  792. ]);
  793. case "XJSSpreadAttribute":
  794. case "JSXSpreadAttribute":
  795. return concat(["{...", path.call(print, "argument"), "}"]);
  796. case "XJSExpressionContainer":
  797. case "JSXExpressionContainer":
  798. return concat(["{", path.call(print, "expression"), "}"]);
  799. case "XJSElement":
  800. case "JSXElement":
  801. var openingLines = path.call(print, "openingElement");
  802. if (n.openingElement.selfClosing) {
  803. assert.ok(!n.closingElement);
  804. return openingLines;
  805. }
  806. var childLines = concat(
  807. path.map(function(childPath) {
  808. var child = childPath.getValue();
  809. if (namedTypes.Literal.check(child) &&
  810. typeof child.value === "string") {
  811. if (/\S/.test(child.value)) {
  812. return child.value.replace(/^\s+|\s+$/g, "");
  813. } else if (/\n/.test(child.value)) {
  814. return "\n";
  815. }
  816. }
  817. return print(childPath);
  818. }, "children")
  819. ).indentTail(options.tabWidth);
  820. var closingLines = path.call(print, "closingElement");
  821. return concat([
  822. openingLines,
  823. childLines,
  824. closingLines
  825. ]);
  826. case "XJSOpeningElement":
  827. case "JSXOpeningElement":
  828. var parts = ["<", path.call(print, "name")];
  829. var attrParts = [];
  830. path.each(function(attrPath) {
  831. attrParts.push(" ", print(attrPath));
  832. }, "attributes");
  833. var attrLines = concat(attrParts);
  834. var needLineWrap = (
  835. attrLines.length > 1 ||
  836. attrLines.getLineLength(1) > options.wrapColumn
  837. );
  838. if (needLineWrap) {
  839. attrParts.forEach(function(part, i) {
  840. if (part === " ") {
  841. assert.strictEqual(i % 2, 0);
  842. attrParts[i] = "\n";
  843. }
  844. });
  845. attrLines = concat(attrParts).indentTail(options.tabWidth);
  846. }
  847. parts.push(attrLines, n.selfClosing ? " />" : ">");
  848. return concat(parts);
  849. case "XJSClosingElement":
  850. case "JSXClosingElement":
  851. return concat(["</", path.call(print, "name"), ">"]);
  852. case "XJSText":
  853. case "JSXText":
  854. return fromString(n.value, options);
  855. case "XJSEmptyExpression":
  856. case "JSXEmptyExpression":
  857. return fromString("");
  858. case "TypeAnnotatedIdentifier":
  859. return concat([
  860. path.call(print, "annotation"),
  861. " ",
  862. path.call(print, "identifier")
  863. ]);
  864. case "ClassBody":
  865. if (n.body.length === 0) {
  866. return fromString("{}");
  867. }
  868. return concat([
  869. "{\n",
  870. path.call(function(bodyPath) {
  871. return printStatementSequence(bodyPath, options, print);
  872. }, "body").indent(options.tabWidth),
  873. "\n}"
  874. ]);
  875. case "ClassPropertyDefinition":
  876. var parts = ["static ", path.call(print, "definition")];
  877. if (!namedTypes.MethodDefinition.check(n.definition))
  878. parts.push(";");
  879. return concat(parts);
  880. case "ClassProperty":
  881. var parts = [];
  882. if (n.static)
  883. parts.push("static ");
  884. parts.push(path.call(print, "key"));
  885. if (n.typeAnnotation)
  886. parts.push(path.call(print, "typeAnnotation"));
  887. if (n.value)
  888. parts.push(" = ", path.call(print, "value"));
  889. parts.push(";");
  890. return concat(parts);
  891. case "ClassDeclaration":
  892. case "ClassExpression":
  893. var parts = [];
  894. parts.push("class");
  895. if (n.id) {
  896. parts.push(
  897. " ",
  898. path.call(print, "id"),
  899. path.call(print, "typeParameters")
  900. );
  901. }
  902. if (n.superClass) {
  903. parts.push(
  904. " extends ",
  905. path.call(print, "superClass"),
  906. path.call(print, "superTypeParameters")
  907. );
  908. }
  909. if (n["implements"] && n['implements'].length > 0) {
  910. parts.push(
  911. " implements ",
  912. fromString(", ").join(path.map(print, "implements"))
  913. );
  914. }
  915. parts.push(" ", path.call(print, "body"));
  916. return concat(parts);
  917. case "TemplateElement":
  918. return fromString(n.value.raw, options).lockIndentTail();
  919. case "TemplateLiteral":
  920. var expressions = path.map(print, "expressions");
  921. var parts = ["`"];
  922. path.each(function(childPath) {
  923. var i = childPath.getName();
  924. parts.push(print(childPath));
  925. if (i < expressions.length) {
  926. parts.push("${", expressions[i], "}");
  927. }
  928. }, "quasis");
  929. parts.push("`");
  930. return concat(parts).lockIndentTail();
  931. case "TaggedTemplateExpression":
  932. return concat([
  933. path.call(print, "tag"),
  934. path.call(print, "quasi")
  935. ]);
  936. // These types are unprintable because they serve as abstract
  937. // supertypes for other (printable) types.
  938. case "Node":
  939. case "Printable":
  940. case "SourceLocation":
  941. case "Position":
  942. case "Statement":
  943. case "Function":
  944. case "Pattern":
  945. case "Expression":
  946. case "Declaration":
  947. case "Specifier":
  948. case "NamedSpecifier":
  949. case "Comment": // Supertype of Block and Line.
  950. case "MemberTypeAnnotation": // Flow
  951. case "TupleTypeAnnotation": // Flow
  952. case "Type": // Flow
  953. throw new Error("unprintable type: " + JSON.stringify(n.type));
  954. case "CommentBlock": // Babel block comment.
  955. case "Block": // Esprima block comment.
  956. return concat(["/*", fromString(n.value, options), "*/"]);
  957. case "CommentLine": // Babel line comment.
  958. case "Line": // Esprima line comment.
  959. return concat(["//", fromString(n.value, options)]);
  960. // Type Annotations for Facebook Flow, typically stripped out or
  961. // transformed away before printing.
  962. case "TypeAnnotation":
  963. var parts = [];
  964. if (n.typeAnnotation) {
  965. if (n.typeAnnotation.type !== "FunctionTypeAnnotation") {
  966. parts.push(": ");
  967. }
  968. parts.push(path.call(print, "typeAnnotation"));
  969. return concat(parts);
  970. }
  971. return fromString("");
  972. case "AnyTypeAnnotation":
  973. return fromString("any", options);
  974. case "MixedTypeAnnotation":
  975. return fromString("mixed", options);
  976. case "ArrayTypeAnnotation":
  977. return concat([
  978. path.call(print, "elementType"),
  979. "[]"
  980. ]);
  981. case "BooleanTypeAnnotation":
  982. return fromString("boolean", options);
  983. case "BooleanLiteralTypeAnnotation":
  984. assert.strictEqual(typeof n.value, "boolean");
  985. return fromString("" + n.value, options);
  986. case "DeclareClass":
  987. return printFlowDeclaration(path, [
  988. "class ",
  989. path.call(print, "id"),
  990. " ",
  991. path.call(print, "body"),
  992. ]);
  993. case "DeclareFunction":
  994. return printFlowDeclaration(path, [
  995. "function ",
  996. path.call(print, "id"),
  997. ";"
  998. ]);
  999. case "DeclareModule":
  1000. return printFlowDeclaration(path, [
  1001. "module ",
  1002. path.call(print, "id"),
  1003. " ",
  1004. path.call(print, "body"),
  1005. ]);
  1006. case "DeclareVariable":
  1007. return printFlowDeclaration(path, [
  1008. "var ",
  1009. path.call(print, "id"),
  1010. ";"
  1011. ]);
  1012. case "DeclareExportDeclaration":
  1013. return concat([
  1014. "declare ",
  1015. printExportDeclaration(path, options, print)
  1016. ]);
  1017. case "FunctionTypeAnnotation":
  1018. // FunctionTypeAnnotation is ambiguous:
  1019. // declare function(a: B): void; OR
  1020. // var A: (a: B) => void;
  1021. var parts = [];
  1022. var parent = path.getParentNode(0);
  1023. var isArrowFunctionTypeAnnotation = !(
  1024. namedTypes.ObjectTypeCallProperty.check(parent) ||
  1025. namedTypes.DeclareFunction.check(path.getParentNode(2))
  1026. );
  1027. var needsColon =
  1028. isArrowFunctionTypeAnnotation &&
  1029. !namedTypes.FunctionTypeParam.check(parent);
  1030. if (needsColon) {
  1031. parts.push(": ");
  1032. }
  1033. parts.push(
  1034. "(",
  1035. fromString(", ").join(path.map(print, "params")),
  1036. ")"
  1037. );
  1038. // The returnType is not wrapped in a TypeAnnotation, so the colon
  1039. // needs to be added separately.
  1040. if (n.returnType) {
  1041. parts.push(
  1042. isArrowFunctionTypeAnnotation ? " => " : ": ",
  1043. path.call(print, "returnType")
  1044. );
  1045. }
  1046. return concat(parts);
  1047. case "FunctionTypeParam":
  1048. return concat([
  1049. path.call(print, "name"),
  1050. ": ",
  1051. path.call(print, "typeAnnotation"),
  1052. ]);
  1053. case "GenericTypeAnnotation":
  1054. return concat([
  1055. path.call(print, "id"),
  1056. path.call(print, "typeParameters")
  1057. ]);
  1058. case "InterfaceDeclaration":
  1059. var parts = [
  1060. fromString("interface ", options),
  1061. path.call(print, "id"),
  1062. path.call(print, "typeParameters"),
  1063. " "
  1064. ];
  1065. if (n["extends"]) {
  1066. parts.push(
  1067. "extends ",
  1068. fromString(", ").join(path.map(print, "extends"))
  1069. );
  1070. }
  1071. parts.push(" ", path.call(print, "body"));
  1072. return concat(parts);
  1073. case "ClassImplements":
  1074. case "InterfaceExtends":
  1075. return concat([
  1076. path.call(print, "id"),
  1077. path.call(print, "typeParameters")
  1078. ]);
  1079. case "IntersectionTypeAnnotation":
  1080. return fromString(" & ").join(path.map(print, "types"));
  1081. case "NullableTypeAnnotation":
  1082. return concat([
  1083. "?",
  1084. path.call(print, "typeAnnotation")
  1085. ]);
  1086. case "NumberTypeAnnotation":
  1087. return fromString("number", options);
  1088. case "ObjectTypeCallProperty":
  1089. return path.call(print, "value");
  1090. case "ObjectTypeIndexer":
  1091. return concat([
  1092. "[",
  1093. path.call(print, "id"),
  1094. ": ",
  1095. path.call(print, "key"),
  1096. "]: ",
  1097. path.call(print, "value")
  1098. ]);
  1099. case "ObjectTypeProperty":
  1100. return concat([
  1101. path.call(print, "key"),
  1102. ": ",
  1103. path.call(print, "value")
  1104. ]);
  1105. case "QualifiedTypeIdentifier":
  1106. return concat([
  1107. path.call(print, "qualification"),
  1108. ".",
  1109. path.call(print, "id")
  1110. ]);
  1111. case "StringLiteralTypeAnnotation":
  1112. return fromString(nodeStr(n.value, options), options);
  1113. case "NumberLiteralTypeAnnotation":
  1114. assert.strictEqual(typeof n.value, "number");
  1115. return fromString("" + n.value, options);
  1116. case "StringTypeAnnotation":
  1117. return fromString("string", options);
  1118. case "TypeAlias":
  1119. return concat([
  1120. "type ",
  1121. path.call(print, "id"),
  1122. " = ",
  1123. path.call(print, "right"),
  1124. ";"
  1125. ]);
  1126. case "TypeCastExpression":
  1127. return concat([
  1128. "(",
  1129. path.call(print, "expression"),
  1130. path.call(print, "typeAnnotation"),
  1131. ")"
  1132. ]);
  1133. case "TypeParameterDeclaration":
  1134. case "TypeParameterInstantiation":
  1135. return concat([
  1136. "<",
  1137. fromString(", ").join(path.map(print, "params")),
  1138. ">"
  1139. ]);
  1140. case "TypeofTypeAnnotation":
  1141. return concat([
  1142. fromString("typeof ", options),
  1143. path.call(print, "argument")
  1144. ]);
  1145. case "UnionTypeAnnotation":
  1146. return fromString(" | ").join(path.map(print, "types"));
  1147. case "VoidTypeAnnotation":
  1148. return fromString("void", options);
  1149. // Unhandled types below. If encountered, nodes of these types should
  1150. // be either left alone or desugared into AST types that are fully
  1151. // supported by the pretty-printer.
  1152. case "ClassHeritage": // TODO
  1153. case "ComprehensionBlock": // TODO
  1154. case "ComprehensionExpression": // TODO
  1155. case "Glob": // TODO
  1156. case "GeneratorExpression": // TODO
  1157. case "LetStatement": // TODO
  1158. case "LetExpression": // TODO
  1159. case "GraphExpression": // TODO
  1160. case "GraphIndexExpression": // TODO
  1161. // XML types that nobody cares about or needs to print.
  1162. case "XMLDefaultDeclaration":
  1163. case "XMLAnyName":
  1164. case "XMLQualifiedIdentifier":
  1165. case "XMLFunctionQualifiedIdentifier":
  1166. case "XMLAttributeSelector":
  1167. case "XMLFilterExpression":
  1168. case "XML":
  1169. case "XMLElement":
  1170. case "XMLList":
  1171. case "XMLEscape":
  1172. case "XMLText":
  1173. case "XMLStartTag":
  1174. case "XMLEndTag":
  1175. case "XMLPointTag":
  1176. case "XMLName":
  1177. case "XMLAttribute":
  1178. case "XMLCdata":
  1179. case "XMLComment":
  1180. case "XMLProcessingInstruction":
  1181. default:
  1182. debugger;
  1183. throw new Error("unknown type: " + JSON.stringify(n.type));
  1184. }
  1185. return p;
  1186. }
  1187. function printStatementSequence(path, options, print) {
  1188. var inClassBody =
  1189. namedTypes.ClassBody &&
  1190. namedTypes.ClassBody.check(path.getParentNode());
  1191. var filtered = [];
  1192. var sawComment = false;
  1193. var sawStatement = false;
  1194. path.each(function(stmtPath) {
  1195. var i = stmtPath.getName();
  1196. var stmt = stmtPath.getValue();
  1197. // Just in case the AST has been modified to contain falsy
  1198. // "statements," it's safer simply to skip them.
  1199. if (!stmt) {
  1200. return;
  1201. }
  1202. // Skip printing EmptyStatement nodes to avoid leaving stray
  1203. // semicolons lying around.
  1204. if (stmt.type === "EmptyStatement") {
  1205. return;
  1206. }
  1207. if (namedTypes.Comment.check(stmt)) {
  1208. // The pretty printer allows a dangling Comment node to act as
  1209. // a Statement when the Comment can't be attached to any other
  1210. // non-Comment node in the tree.
  1211. sawComment = true;
  1212. } else if (namedTypes.Statement.check(stmt)) {
  1213. sawStatement = true;
  1214. } else {
  1215. // When the pretty printer encounters a string instead of an
  1216. // AST node, it just prints the string. This behavior can be
  1217. // useful for fine-grained formatting decisions like inserting
  1218. // blank lines.
  1219. isString.assert(stmt);
  1220. }
  1221. // We can't hang onto stmtPath outside of this function, because
  1222. // it's just a reference to a mutable FastPath object, so we have
  1223. // to go ahead and print it here.
  1224. filtered.push({
  1225. node: stmt,
  1226. printed: print(stmtPath)
  1227. });
  1228. });
  1229. if (sawComment) {
  1230. assert.strictEqual(
  1231. sawStatement, false,
  1232. "Comments may appear as statements in otherwise empty statement " +
  1233. "lists, but may not coexist with non-Comment nodes."
  1234. );
  1235. }
  1236. var prevTrailingSpace = null;
  1237. var len = filtered.length;
  1238. var parts = [];
  1239. filtered.forEach(function(info, i) {
  1240. var printed = info.printed;
  1241. var stmt = info.node;
  1242. var multiLine = printed.length > 1;
  1243. var notFirst = i > 0;
  1244. var notLast = i < len - 1;
  1245. var leadingSpace;
  1246. var trailingSpace;
  1247. var lines = stmt && stmt.loc && stmt.loc.lines;
  1248. var trueLoc = lines && options.reuseWhitespace &&
  1249. util.getTrueLoc(stmt, lines);
  1250. if (notFirst) {
  1251. if (trueLoc) {
  1252. var beforeStart = lines.skipSpaces(trueLoc.start, true);
  1253. var beforeStartLine = beforeStart ? beforeStart.line : 1;
  1254. var leadingGap = trueLoc.start.line - beforeStartLine;
  1255. leadingSpace = Array(leadingGap + 1).join("\n");
  1256. } else {
  1257. leadingSpace = multiLine ? "\n\n" : "\n";
  1258. }
  1259. } else {
  1260. leadingSpace = "";
  1261. }
  1262. if (notLast) {
  1263. if (trueLoc) {
  1264. var afterEnd = lines.skipSpaces(trueLoc.end);
  1265. var afterEndLine = afterEnd ? afterEnd.line : lines.length;
  1266. var trailingGap = afterEndLine - trueLoc.end.line;
  1267. trailingSpace = Array(trailingGap + 1).join("\n");
  1268. } else {
  1269. trailingSpace = multiLine ? "\n\n" : "\n";
  1270. }
  1271. } else {
  1272. trailingSpace = "";
  1273. }
  1274. parts.push(
  1275. maxSpace(prevTrailingSpace, leadingSpace),
  1276. printed
  1277. );
  1278. if (notLast) {
  1279. prevTrailingSpace = trailingSpace;
  1280. } else if (trailingSpace) {
  1281. parts.push(trailingSpace);
  1282. }
  1283. });
  1284. return concat(parts);
  1285. }
  1286. function maxSpace(s1, s2) {
  1287. if (!s1 && !s2) {
  1288. return fromString("");
  1289. }
  1290. if (!s1) {
  1291. return fromString(s2);
  1292. }
  1293. if (!s2) {
  1294. return fromString(s1);
  1295. }
  1296. var spaceLines1 = fromString(s1);
  1297. var spaceLines2 = fromString(s2);
  1298. if (spaceLines2.length > spaceLines1.length) {
  1299. return spaceLines2;
  1300. }
  1301. return spaceLines1;
  1302. }
  1303. function printMethod(path, options, print) {
  1304. var node = path.getNode();
  1305. var kind = node.kind;
  1306. var parts = [];
  1307. namedTypes.FunctionExpression.assert(node.value);
  1308. if (node.value.async) {
  1309. parts.push("async ");
  1310. }
  1311. if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
  1312. if (node.value.generator) {
  1313. parts.push("*");
  1314. }
  1315. } else {
  1316. assert.ok(kind === "get" || kind === "set");
  1317. parts.push(kind, " ");
  1318. }
  1319. var key = path.call(print, "key");
  1320. if (node.computed) {
  1321. key = concat(["[", key, "]"]);
  1322. }
  1323. parts.push(
  1324. key,
  1325. path.call(print, "value", "typeParameters"),
  1326. "(",
  1327. path.call(function(valuePath) {
  1328. return printFunctionParams(valuePath, options, print);
  1329. }, "value"),
  1330. ")",
  1331. path.call(print, "value", "returnType"),
  1332. " ",
  1333. path.call(print, "value", "body")
  1334. );
  1335. return concat(parts);
  1336. }
  1337. function printArgumentsList(path, options, print) {
  1338. var printed = path.map(print, "arguments");
  1339. var joined = fromString(", ").join(printed);
  1340. if (joined.getLineLength(1) > options.wrapColumn) {
  1341. joined = fromString(",\n").join(printed);
  1342. return concat([
  1343. "(\n",
  1344. joined.indent(options.tabWidth),
  1345. options.trailingComma ? ",\n)" : "\n)"
  1346. ]);
  1347. }
  1348. return concat(["(", joined, ")"]);
  1349. }
  1350. function printFunctionParams(path, options, print) {
  1351. var fun = path.getValue();
  1352. namedTypes.Function.assert(fun);
  1353. var printed = path.map(print, "params");
  1354. if (fun.defaults) {
  1355. path.each(function(defExprPath) {
  1356. var i = defExprPath.getName();
  1357. var p = printed[i];
  1358. if (p && defExprPath.getValue()) {
  1359. printed[i] = concat([p, "=", print(defExprPath)]);
  1360. }
  1361. }, "defaults");
  1362. }
  1363. if (fun.rest) {
  1364. printed.push(concat(["...", path.call(print, "rest")]));
  1365. }
  1366. var joined = fromString(", ").join(printed);
  1367. if (joined.length > 1 ||
  1368. joined.getLineLength(1) > options.wrapColumn) {
  1369. joined = fromString(",\n").join(printed);
  1370. if (options.trailingComma && !fun.rest) {
  1371. joined = concat([joined, ",\n"]);
  1372. }
  1373. return concat(["\n", joined.indent(options.tabWidth)]);
  1374. }
  1375. return joined;
  1376. }
  1377. function printExportDeclaration(path, options, print) {
  1378. var decl = path.getValue();
  1379. var parts = ["export "];
  1380. namedTypes.Declaration.assert(decl);
  1381. if (decl["default"] ||
  1382. decl.type === "ExportDefaultDeclaration") {
  1383. parts.push("default ");
  1384. }
  1385. if (decl.declaration) {
  1386. parts.push(path.call(print, "declaration"));
  1387. } else if (decl.specifiers &&
  1388. decl.specifiers.length > 0) {
  1389. if (decl.specifiers.length === 1 &&
  1390. decl.specifiers[0].type === "ExportBatchSpecifier") {
  1391. parts.push("*");
  1392. } else {
  1393. parts.push(
  1394. "{",
  1395. fromString(", ").join(path.map(print, "specifiers")),
  1396. "}"
  1397. );
  1398. }
  1399. if (decl.source) {
  1400. parts.push(" from ", path.call(print, "source"));
  1401. }
  1402. }
  1403. var lines = concat(parts);
  1404. if (lastNonSpaceCharacter(lines) !== ";") {
  1405. lines = concat([lines, ";"]);
  1406. }
  1407. return lines;
  1408. }
  1409. function printFlowDeclaration(path, parts) {
  1410. var parentExportDecl = util.getParentExportDeclaration(path);
  1411. if (parentExportDecl) {
  1412. assert.strictEqual(
  1413. parentExportDecl.type,
  1414. "DeclareExportDeclaration"
  1415. );
  1416. } else {
  1417. // If the parent node has type DeclareExportDeclaration, then it
  1418. // will be responsible for printing the "declare" token. Otherwise
  1419. // it needs to be printed with this non-exported declaration node.
  1420. parts.unshift("declare ");
  1421. }
  1422. return concat(parts);
  1423. }
  1424. function adjustClause(clause, options) {
  1425. if (clause.length > 1)
  1426. return concat([" ", clause]);
  1427. return concat([
  1428. "\n",
  1429. maybeAddSemicolon(clause).indent(options.tabWidth)
  1430. ]);
  1431. }
  1432. function lastNonSpaceCharacter(lines) {
  1433. var pos = lines.lastPos();
  1434. do {
  1435. var ch = lines.charAt(pos);
  1436. if (/\S/.test(ch))
  1437. return ch;
  1438. } while (lines.prevPos(pos));
  1439. }
  1440. function endsWithBrace(lines) {
  1441. return lastNonSpaceCharacter(lines) === "}";
  1442. }
  1443. function swapQuotes(str) {
  1444. return str.replace(/['"]/g, function(m) {
  1445. return m === '"' ? '\'' : '"';
  1446. });
  1447. }
  1448. function nodeStr(str, options) {
  1449. isString.assert(str);
  1450. switch (options.quote) {
  1451. case "auto":
  1452. var double = JSON.stringify(str);
  1453. var single = swapQuotes(JSON.stringify(swapQuotes(str)));
  1454. return double.length > single.length ? single : double;
  1455. case "single":
  1456. return swapQuotes(JSON.stringify(swapQuotes(str)));
  1457. case "double":
  1458. default:
  1459. return JSON.stringify(str);
  1460. }
  1461. }
  1462. function maybeAddSemicolon(lines) {
  1463. var eoc = lastNonSpaceCharacter(lines);
  1464. if (!eoc || "\n};".indexOf(eoc) < 0)
  1465. return concat([lines, ";"]);
  1466. return lines;
  1467. }