printer.js 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010
  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. var parts = [];
  178. switch (n.type) {
  179. case "File":
  180. return path.call(print, "program");
  181. case "Program":
  182. // Babel 6
  183. if (n.directives) {
  184. path.each(function(childPath) {
  185. parts.push(print(childPath), ";\n");
  186. }, "directives");
  187. }
  188. parts.push(path.call(function(bodyPath) {
  189. return printStatementSequence(bodyPath, options, print);
  190. }, "body"));
  191. return concat(parts);
  192. case "Noop": // Babel extension.
  193. case "EmptyStatement":
  194. return fromString("");
  195. case "ExpressionStatement":
  196. return concat([path.call(print, "expression"), ";"]);
  197. case "ParenthesizedExpression": // Babel extension.
  198. return concat(["(", path.call(print, "expression"), ")"]);
  199. case "BinaryExpression":
  200. case "LogicalExpression":
  201. case "AssignmentExpression":
  202. return fromString(" ").join([
  203. path.call(print, "left"),
  204. n.operator,
  205. path.call(print, "right")
  206. ]);
  207. case "AssignmentPattern":
  208. return concat([
  209. path.call(print, "left"),
  210. " = ",
  211. path.call(print, "right")
  212. ]);
  213. case "MemberExpression":
  214. parts.push(path.call(print, "object"));
  215. var property = path.call(print, "property");
  216. if (n.computed) {
  217. parts.push("[", property, "]");
  218. } else {
  219. parts.push(".", property);
  220. }
  221. return concat(parts);
  222. case "MetaProperty":
  223. return concat([
  224. path.call(print, "meta"),
  225. ".",
  226. path.call(print, "property")
  227. ]);
  228. case "BindExpression":
  229. if (n.object) {
  230. parts.push(path.call(print, "object"));
  231. }
  232. parts.push("::", path.call(print, "callee"));
  233. return concat(parts);
  234. case "Path":
  235. return fromString(".").join(n.body);
  236. case "Identifier":
  237. return concat([
  238. fromString(n.name, options),
  239. path.call(print, "typeAnnotation")
  240. ]);
  241. case "SpreadElement":
  242. case "SpreadElementPattern":
  243. case "RestProperty": // Babel 6 for ObjectPattern
  244. case "SpreadProperty":
  245. case "SpreadPropertyPattern":
  246. case "RestElement":
  247. return concat(["...", path.call(print, "argument")]);
  248. case "FunctionDeclaration":
  249. case "FunctionExpression":
  250. if (n.async)
  251. parts.push("async ");
  252. parts.push("function");
  253. if (n.generator)
  254. parts.push("*");
  255. if (n.id) {
  256. parts.push(
  257. " ",
  258. path.call(print, "id"),
  259. path.call(print, "typeParameters")
  260. );
  261. }
  262. parts.push(
  263. "(",
  264. printFunctionParams(path, options, print),
  265. ")",
  266. path.call(print, "returnType"),
  267. " ",
  268. path.call(print, "body")
  269. );
  270. return concat(parts);
  271. case "ArrowFunctionExpression":
  272. if (n.async)
  273. parts.push("async ");
  274. if (n.typeParameters) {
  275. parts.push(path.call(print, "typeParameters"));
  276. }
  277. if (
  278. !options.arrowParensAlways &&
  279. n.params.length === 1 &&
  280. !n.rest &&
  281. n.params[0].type === 'Identifier' &&
  282. !n.params[0].typeAnnotation &&
  283. !n.returnType
  284. ) {
  285. parts.push(path.call(print, "params", 0));
  286. } else {
  287. parts.push(
  288. "(",
  289. printFunctionParams(path, options, print),
  290. ")",
  291. path.call(print, "returnType")
  292. );
  293. }
  294. parts.push(" => ", path.call(print, "body"));
  295. return concat(parts);
  296. case "MethodDefinition":
  297. if (n.static) {
  298. parts.push("static ");
  299. }
  300. parts.push(printMethod(path, options, print));
  301. return concat(parts);
  302. case "YieldExpression":
  303. parts.push("yield");
  304. if (n.delegate)
  305. parts.push("*");
  306. if (n.argument)
  307. parts.push(" ", path.call(print, "argument"));
  308. return concat(parts);
  309. case "AwaitExpression":
  310. parts.push("await");
  311. if (n.all)
  312. parts.push("*");
  313. if (n.argument)
  314. parts.push(" ", path.call(print, "argument"));
  315. return concat(parts);
  316. case "ModuleDeclaration":
  317. parts.push("module", path.call(print, "id"));
  318. if (n.source) {
  319. assert.ok(!n.body);
  320. parts.push("from", path.call(print, "source"));
  321. } else {
  322. parts.push(path.call(print, "body"));
  323. }
  324. return fromString(" ").join(parts);
  325. case "ImportSpecifier":
  326. if (n.imported) {
  327. parts.push(path.call(print, "imported"));
  328. if (n.local &&
  329. n.local.name !== n.imported.name) {
  330. parts.push(" as ", path.call(print, "local"));
  331. }
  332. } else if (n.id) {
  333. parts.push(path.call(print, "id"));
  334. if (n.name) {
  335. parts.push(" as ", path.call(print, "name"));
  336. }
  337. }
  338. return concat(parts);
  339. case "ExportSpecifier":
  340. if (n.local) {
  341. parts.push(path.call(print, "local"));
  342. if (n.exported &&
  343. n.exported.name !== n.local.name) {
  344. parts.push(" as ", path.call(print, "exported"));
  345. }
  346. } else if (n.id) {
  347. parts.push(path.call(print, "id"));
  348. if (n.name) {
  349. parts.push(" as ", path.call(print, "name"));
  350. }
  351. }
  352. return concat(parts);
  353. case "ExportBatchSpecifier":
  354. return fromString("*");
  355. case "ImportNamespaceSpecifier":
  356. parts.push("* as ");
  357. if (n.local) {
  358. parts.push(path.call(print, "local"));
  359. } else if (n.id) {
  360. parts.push(path.call(print, "id"));
  361. }
  362. return concat(parts);
  363. case "ImportDefaultSpecifier":
  364. if (n.local) {
  365. return path.call(print, "local");
  366. }
  367. return path.call(print, "id");
  368. case "ExportDeclaration":
  369. case "ExportDefaultDeclaration":
  370. case "ExportNamedDeclaration":
  371. return printExportDeclaration(path, options, print);
  372. case "ExportAllDeclaration":
  373. parts.push("export *");
  374. if (n.exported) {
  375. parts.push(" as ", path.call(print, "exported"));
  376. }
  377. parts.push(
  378. " from ",
  379. path.call(print, "source")
  380. );
  381. return concat(parts);
  382. case "ExportNamespaceSpecifier":
  383. return concat(["* as ", path.call(print, "exported")]);
  384. case "ExportDefaultSpecifier":
  385. return path.call(print, "exported");
  386. case "Import":
  387. return fromString("import", options);
  388. case "ImportDeclaration":
  389. parts.push("import ");
  390. if (n.importKind && n.importKind !== "value") {
  391. parts.push(n.importKind + " ");
  392. }
  393. if (n.specifiers &&
  394. n.specifiers.length > 0) {
  395. var foundImportSpecifier = false;
  396. path.each(function(specifierPath) {
  397. var i = specifierPath.getName();
  398. if (i > 0) {
  399. parts.push(", ");
  400. }
  401. var value = specifierPath.getValue();
  402. if (namedTypes.ImportDefaultSpecifier.check(value) ||
  403. namedTypes.ImportNamespaceSpecifier.check(value)) {
  404. assert.strictEqual(foundImportSpecifier, false);
  405. } else {
  406. namedTypes.ImportSpecifier.assert(value);
  407. if (!foundImportSpecifier) {
  408. foundImportSpecifier = true;
  409. parts.push(
  410. options.objectCurlySpacing ? "{ " : "{"
  411. );
  412. }
  413. }
  414. parts.push(print(specifierPath));
  415. }, "specifiers");
  416. if (foundImportSpecifier) {
  417. parts.push(
  418. options.objectCurlySpacing ? " }" : "}"
  419. );
  420. }
  421. parts.push(" from ");
  422. }
  423. parts.push(path.call(print, "source"), ";");
  424. return concat(parts);
  425. case "BlockStatement":
  426. var naked = path.call(function(bodyPath) {
  427. return printStatementSequence(bodyPath, options, print);
  428. }, "body");
  429. if (naked.isEmpty()) {
  430. if (!n.directives || n.directives.length === 0) {
  431. return fromString("{}");
  432. }
  433. }
  434. parts.push("{\n");
  435. // Babel 6
  436. if (n.directives) {
  437. path.each(function(childPath) {
  438. parts.push(
  439. print(childPath).indent(options.tabWidth),
  440. ";",
  441. n.directives.length > 1 || !naked.isEmpty() ? "\n" : ""
  442. );
  443. }, "directives");
  444. }
  445. parts.push(naked.indent(options.tabWidth));
  446. parts.push("\n}");
  447. return concat(parts);
  448. case "ReturnStatement":
  449. parts.push("return");
  450. if (n.argument) {
  451. var argLines = path.call(print, "argument");
  452. if (argLines.startsWithComment() ||
  453. (argLines.length > 1 &&
  454. namedTypes.JSXElement &&
  455. namedTypes.JSXElement.check(n.argument)
  456. )) {
  457. parts.push(
  458. " (\n",
  459. argLines.indent(options.tabWidth),
  460. "\n)"
  461. );
  462. } else {
  463. parts.push(" ", argLines);
  464. }
  465. }
  466. parts.push(";");
  467. return concat(parts);
  468. case "CallExpression":
  469. return concat([
  470. path.call(print, "callee"),
  471. printArgumentsList(path, options, print)
  472. ]);
  473. case "ObjectExpression":
  474. case "ObjectPattern":
  475. case "ObjectTypeAnnotation":
  476. var allowBreak = false;
  477. var isTypeAnnotation = n.type === "ObjectTypeAnnotation";
  478. var separator = options.flowObjectCommas ? "," : (isTypeAnnotation ? ";" : ",");
  479. var fields = [];
  480. if (isTypeAnnotation) {
  481. fields.push("indexers", "callProperties");
  482. }
  483. fields.push("properties");
  484. var len = 0;
  485. fields.forEach(function(field) {
  486. len += n[field].length;
  487. });
  488. var oneLine = (isTypeAnnotation && len === 1) || len === 0;
  489. var leftBrace = n.exact ? "{|" : "{";
  490. var rightBrace = n.exact ? "|}" : "}";
  491. parts.push(oneLine ? leftBrace : leftBrace + "\n");
  492. var leftBraceIndex = parts.length - 1;
  493. var i = 0;
  494. fields.forEach(function(field) {
  495. path.each(function(childPath) {
  496. var lines = print(childPath);
  497. if (!oneLine) {
  498. lines = lines.indent(options.tabWidth);
  499. }
  500. var multiLine = !isTypeAnnotation && lines.length > 1;
  501. if (multiLine && allowBreak) {
  502. // Similar to the logic for BlockStatement.
  503. parts.push("\n");
  504. }
  505. parts.push(lines);
  506. if (i < len - 1) {
  507. // Add an extra line break if the previous object property
  508. // had a multi-line value.
  509. parts.push(separator + (multiLine ? "\n\n" : "\n"));
  510. allowBreak = !multiLine;
  511. } else if (len !== 1 && isTypeAnnotation) {
  512. parts.push(separator);
  513. } else if (!oneLine && util.isTrailingCommaEnabled(options, "objects")) {
  514. parts.push(separator);
  515. }
  516. i++;
  517. }, field);
  518. });
  519. parts.push(oneLine ? rightBrace : "\n" + rightBrace);
  520. if (i !== 0 && oneLine && options.objectCurlySpacing) {
  521. parts[leftBraceIndex] = leftBrace + " ";
  522. parts[parts.length - 1] = " " + rightBrace;
  523. }
  524. return concat(parts);
  525. case "PropertyPattern":
  526. return concat([
  527. path.call(print, "key"),
  528. ": ",
  529. path.call(print, "pattern")
  530. ]);
  531. case "ObjectProperty": // Babel 6
  532. case "Property": // Non-standard AST node type.
  533. if (n.method || n.kind === "get" || n.kind === "set") {
  534. return printMethod(path, options, print);
  535. }
  536. var key = path.call(print, "key");
  537. if (n.computed) {
  538. parts.push("[", key, "]");
  539. } else {
  540. parts.push(key);
  541. }
  542. if (! n.shorthand) {
  543. parts.push(": ", path.call(print, "value"));
  544. }
  545. return concat(parts);
  546. case "ClassMethod": // Babel 6
  547. if (n.static) {
  548. parts.push("static ");
  549. }
  550. return concat([parts, printObjectMethod(path, options, print)]);
  551. case "ObjectMethod": // Babel 6
  552. return printObjectMethod(path, options, print);
  553. case "Decorator":
  554. return concat(["@", path.call(print, "expression")]);
  555. case "ArrayExpression":
  556. case "ArrayPattern":
  557. var elems = n.elements,
  558. len = elems.length;
  559. var printed = path.map(print, "elements");
  560. var joined = fromString(", ").join(printed);
  561. var oneLine = joined.getLineLength(1) <= options.wrapColumn;
  562. if (oneLine) {
  563. if (options.arrayBracketSpacing) {
  564. parts.push("[ ");
  565. } else {
  566. parts.push("[");
  567. }
  568. } else {
  569. parts.push("[\n");
  570. }
  571. path.each(function(elemPath) {
  572. var i = elemPath.getName();
  573. var elem = elemPath.getValue();
  574. if (!elem) {
  575. // If the array expression ends with a hole, that hole
  576. // will be ignored by the interpreter, but if it ends with
  577. // two (or more) holes, we need to write out two (or more)
  578. // commas so that the resulting code is interpreted with
  579. // both (all) of the holes.
  580. parts.push(",");
  581. } else {
  582. var lines = printed[i];
  583. if (oneLine) {
  584. if (i > 0)
  585. parts.push(" ");
  586. } else {
  587. lines = lines.indent(options.tabWidth);
  588. }
  589. parts.push(lines);
  590. if (i < len - 1 || (!oneLine && util.isTrailingCommaEnabled(options, "arrays")))
  591. parts.push(",");
  592. if (!oneLine)
  593. parts.push("\n");
  594. }
  595. }, "elements");
  596. if (oneLine && options.arrayBracketSpacing) {
  597. parts.push(" ]");
  598. } else {
  599. parts.push("]");
  600. }
  601. return concat(parts);
  602. case "SequenceExpression":
  603. return fromString(", ").join(path.map(print, "expressions"));
  604. case "ThisExpression":
  605. return fromString("this");
  606. case "Super":
  607. return fromString("super");
  608. case "NullLiteral": // Babel 6 Literal split
  609. return fromString("null");
  610. case "RegExpLiteral": // Babel 6 Literal split
  611. return fromString(n.extra.raw);
  612. case "BooleanLiteral": // Babel 6 Literal split
  613. case "NumericLiteral": // Babel 6 Literal split
  614. case "StringLiteral": // Babel 6 Literal split
  615. case "Literal":
  616. if (typeof n.value !== "string")
  617. return fromString(n.value, options);
  618. return fromString(nodeStr(n.value, options), options);
  619. case "Directive": // Babel 6
  620. return path.call(print, "value");
  621. case "DirectiveLiteral": // Babel 6
  622. return fromString(nodeStr(n.value, options));
  623. case "ModuleSpecifier":
  624. if (n.local) {
  625. throw new Error(
  626. "The ESTree ModuleSpecifier type should be abstract"
  627. );
  628. }
  629. // The Esprima ModuleSpecifier type is just a string-valued
  630. // Literal identifying the imported-from module.
  631. return fromString(nodeStr(n.value, options), options);
  632. case "UnaryExpression":
  633. parts.push(n.operator);
  634. if (/[a-z]$/.test(n.operator))
  635. parts.push(" ");
  636. parts.push(path.call(print, "argument"));
  637. return concat(parts);
  638. case "UpdateExpression":
  639. parts.push(
  640. path.call(print, "argument"),
  641. n.operator
  642. );
  643. if (n.prefix)
  644. parts.reverse();
  645. return concat(parts);
  646. case "ConditionalExpression":
  647. return concat([
  648. "(", path.call(print, "test"),
  649. " ? ", path.call(print, "consequent"),
  650. " : ", path.call(print, "alternate"), ")"
  651. ]);
  652. case "NewExpression":
  653. parts.push("new ", path.call(print, "callee"));
  654. var args = n.arguments;
  655. if (args) {
  656. parts.push(printArgumentsList(path, options, print));
  657. }
  658. return concat(parts);
  659. case "VariableDeclaration":
  660. parts.push(n.kind, " ");
  661. var maxLen = 0;
  662. var printed = path.map(function(childPath) {
  663. var lines = print(childPath);
  664. maxLen = Math.max(lines.length, maxLen);
  665. return lines;
  666. }, "declarations");
  667. if (maxLen === 1) {
  668. parts.push(fromString(", ").join(printed));
  669. } else if (printed.length > 1 ) {
  670. parts.push(
  671. fromString(",\n").join(printed)
  672. .indentTail(n.kind.length + 1)
  673. );
  674. } else {
  675. parts.push(printed[0]);
  676. }
  677. // We generally want to terminate all variable declarations with a
  678. // semicolon, except when they are children of for loops.
  679. var parentNode = path.getParentNode();
  680. if (!namedTypes.ForStatement.check(parentNode) &&
  681. !namedTypes.ForInStatement.check(parentNode) &&
  682. !(namedTypes.ForOfStatement &&
  683. namedTypes.ForOfStatement.check(parentNode)) &&
  684. !(namedTypes.ForAwaitStatement &&
  685. namedTypes.ForAwaitStatement.check(parentNode))) {
  686. parts.push(";");
  687. }
  688. return concat(parts);
  689. case "VariableDeclarator":
  690. return n.init ? fromString(" = ").join([
  691. path.call(print, "id"),
  692. path.call(print, "init")
  693. ]) : path.call(print, "id");
  694. case "WithStatement":
  695. return concat([
  696. "with (",
  697. path.call(print, "object"),
  698. ") ",
  699. path.call(print, "body")
  700. ]);
  701. case "IfStatement":
  702. var con = adjustClause(path.call(print, "consequent"), options),
  703. parts = ["if (", path.call(print, "test"), ")", con];
  704. if (n.alternate)
  705. parts.push(
  706. endsWithBrace(con) ? " else" : "\nelse",
  707. adjustClause(path.call(print, "alternate"), options));
  708. return concat(parts);
  709. case "ForStatement":
  710. // TODO Get the for (;;) case right.
  711. var init = path.call(print, "init"),
  712. sep = init.length > 1 ? ";\n" : "; ",
  713. forParen = "for (",
  714. indented = fromString(sep).join([
  715. init,
  716. path.call(print, "test"),
  717. path.call(print, "update")
  718. ]).indentTail(forParen.length),
  719. head = concat([forParen, indented, ")"]),
  720. clause = adjustClause(path.call(print, "body"), options),
  721. parts = [head];
  722. if (head.length > 1) {
  723. parts.push("\n");
  724. clause = clause.trimLeft();
  725. }
  726. parts.push(clause);
  727. return concat(parts);
  728. case "WhileStatement":
  729. return concat([
  730. "while (",
  731. path.call(print, "test"),
  732. ")",
  733. adjustClause(path.call(print, "body"), options)
  734. ]);
  735. case "ForInStatement":
  736. // Note: esprima can't actually parse "for each (".
  737. return concat([
  738. n.each ? "for each (" : "for (",
  739. path.call(print, "left"),
  740. " in ",
  741. path.call(print, "right"),
  742. ")",
  743. adjustClause(path.call(print, "body"), options)
  744. ]);
  745. case "ForOfStatement":
  746. return concat([
  747. "for (",
  748. path.call(print, "left"),
  749. " of ",
  750. path.call(print, "right"),
  751. ")",
  752. adjustClause(path.call(print, "body"), options)
  753. ]);
  754. case "ForAwaitStatement":
  755. return concat([
  756. "for await (",
  757. path.call(print, "left"),
  758. " of ",
  759. path.call(print, "right"),
  760. ")",
  761. adjustClause(path.call(print, "body"), options)
  762. ]);
  763. case "DoWhileStatement":
  764. var doBody = concat([
  765. "do",
  766. adjustClause(path.call(print, "body"), options)
  767. ]), parts = [doBody];
  768. if (endsWithBrace(doBody))
  769. parts.push(" while");
  770. else
  771. parts.push("\nwhile");
  772. parts.push(" (", path.call(print, "test"), ");");
  773. return concat(parts);
  774. case "DoExpression":
  775. var statements = path.call(function(bodyPath) {
  776. return printStatementSequence(bodyPath, options, print);
  777. }, "body");
  778. return concat([
  779. "do {\n",
  780. statements.indent(options.tabWidth),
  781. "\n}"
  782. ]);
  783. case "BreakStatement":
  784. parts.push("break");
  785. if (n.label)
  786. parts.push(" ", path.call(print, "label"));
  787. parts.push(";");
  788. return concat(parts);
  789. case "ContinueStatement":
  790. parts.push("continue");
  791. if (n.label)
  792. parts.push(" ", path.call(print, "label"));
  793. parts.push(";");
  794. return concat(parts);
  795. case "LabeledStatement":
  796. return concat([
  797. path.call(print, "label"),
  798. ":\n",
  799. path.call(print, "body")
  800. ]);
  801. case "TryStatement":
  802. parts.push(
  803. "try ",
  804. path.call(print, "block")
  805. );
  806. if (n.handler) {
  807. parts.push(" ", path.call(print, "handler"));
  808. } else if (n.handlers) {
  809. path.each(function(handlerPath) {
  810. parts.push(" ", print(handlerPath));
  811. }, "handlers");
  812. }
  813. if (n.finalizer) {
  814. parts.push(" finally ", path.call(print, "finalizer"));
  815. }
  816. return concat(parts);
  817. case "CatchClause":
  818. parts.push("catch (", path.call(print, "param"));
  819. if (n.guard)
  820. // Note: esprima does not recognize conditional catch clauses.
  821. parts.push(" if ", path.call(print, "guard"));
  822. parts.push(") ", path.call(print, "body"));
  823. return concat(parts);
  824. case "ThrowStatement":
  825. return concat(["throw ", path.call(print, "argument"), ";"]);
  826. case "SwitchStatement":
  827. return concat([
  828. "switch (",
  829. path.call(print, "discriminant"),
  830. ") {\n",
  831. fromString("\n").join(path.map(print, "cases")),
  832. "\n}"
  833. ]);
  834. // Note: ignoring n.lexical because it has no printing consequences.
  835. case "SwitchCase":
  836. if (n.test)
  837. parts.push("case ", path.call(print, "test"), ":");
  838. else
  839. parts.push("default:");
  840. if (n.consequent.length > 0) {
  841. parts.push("\n", path.call(function(consequentPath) {
  842. return printStatementSequence(consequentPath, options, print);
  843. }, "consequent").indent(options.tabWidth));
  844. }
  845. return concat(parts);
  846. case "DebuggerStatement":
  847. return fromString("debugger;");
  848. // JSX extensions below.
  849. case "JSXAttribute":
  850. parts.push(path.call(print, "name"));
  851. if (n.value)
  852. parts.push("=", path.call(print, "value"));
  853. return concat(parts);
  854. case "JSXIdentifier":
  855. return fromString(n.name, options);
  856. case "JSXNamespacedName":
  857. return fromString(":").join([
  858. path.call(print, "namespace"),
  859. path.call(print, "name")
  860. ]);
  861. case "JSXMemberExpression":
  862. return fromString(".").join([
  863. path.call(print, "object"),
  864. path.call(print, "property")
  865. ]);
  866. case "JSXSpreadAttribute":
  867. return concat(["{...", path.call(print, "argument"), "}"]);
  868. case "JSXExpressionContainer":
  869. return concat(["{", path.call(print, "expression"), "}"]);
  870. case "JSXElement":
  871. var openingLines = path.call(print, "openingElement");
  872. if (n.openingElement.selfClosing) {
  873. assert.ok(!n.closingElement);
  874. return openingLines;
  875. }
  876. var childLines = concat(
  877. path.map(function(childPath) {
  878. var child = childPath.getValue();
  879. if (namedTypes.Literal.check(child) &&
  880. typeof child.value === "string") {
  881. if (/\S/.test(child.value)) {
  882. return child.value.replace(/^\s+|\s+$/g, "");
  883. } else if (/\n/.test(child.value)) {
  884. return "\n";
  885. }
  886. }
  887. return print(childPath);
  888. }, "children")
  889. ).indentTail(options.tabWidth);
  890. var closingLines = path.call(print, "closingElement");
  891. return concat([
  892. openingLines,
  893. childLines,
  894. closingLines
  895. ]);
  896. case "JSXOpeningElement":
  897. parts.push("<", path.call(print, "name"));
  898. var attrParts = [];
  899. path.each(function(attrPath) {
  900. attrParts.push(" ", print(attrPath));
  901. }, "attributes");
  902. var attrLines = concat(attrParts);
  903. var needLineWrap = (
  904. attrLines.length > 1 ||
  905. attrLines.getLineLength(1) > options.wrapColumn
  906. );
  907. if (needLineWrap) {
  908. attrParts.forEach(function(part, i) {
  909. if (part === " ") {
  910. assert.strictEqual(i % 2, 0);
  911. attrParts[i] = "\n";
  912. }
  913. });
  914. attrLines = concat(attrParts).indentTail(options.tabWidth);
  915. }
  916. parts.push(attrLines, n.selfClosing ? " />" : ">");
  917. return concat(parts);
  918. case "JSXClosingElement":
  919. return concat(["</", path.call(print, "name"), ">"]);
  920. case "JSXText":
  921. return fromString(n.value, options);
  922. case "JSXEmptyExpression":
  923. return fromString("");
  924. case "TypeAnnotatedIdentifier":
  925. return concat([
  926. path.call(print, "annotation"),
  927. " ",
  928. path.call(print, "identifier")
  929. ]);
  930. case "ClassBody":
  931. if (n.body.length === 0) {
  932. return fromString("{}");
  933. }
  934. return concat([
  935. "{\n",
  936. path.call(function(bodyPath) {
  937. return printStatementSequence(bodyPath, options, print);
  938. }, "body").indent(options.tabWidth),
  939. "\n}"
  940. ]);
  941. case "ClassPropertyDefinition":
  942. parts.push("static ", path.call(print, "definition"));
  943. if (!namedTypes.MethodDefinition.check(n.definition))
  944. parts.push(";");
  945. return concat(parts);
  946. case "ClassProperty":
  947. if (n.static)
  948. parts.push("static ");
  949. var key = path.call(print, "key");
  950. if (n.computed) {
  951. key = concat(["[", key, "]"]);
  952. } else if (n.variance === "plus") {
  953. key = concat(["+", key]);
  954. } else if (n.variance === "minus") {
  955. key = concat(["-", key]);
  956. }
  957. parts.push(key);
  958. if (n.typeAnnotation)
  959. parts.push(path.call(print, "typeAnnotation"));
  960. if (n.value)
  961. parts.push(" = ", path.call(print, "value"));
  962. parts.push(";");
  963. return concat(parts);
  964. case "ClassDeclaration":
  965. case "ClassExpression":
  966. parts.push("class");
  967. if (n.id) {
  968. parts.push(
  969. " ",
  970. path.call(print, "id"),
  971. path.call(print, "typeParameters")
  972. );
  973. }
  974. if (n.superClass) {
  975. parts.push(
  976. " extends ",
  977. path.call(print, "superClass"),
  978. path.call(print, "superTypeParameters")
  979. );
  980. }
  981. if (n["implements"] && n['implements'].length > 0) {
  982. parts.push(
  983. " implements ",
  984. fromString(", ").join(path.map(print, "implements"))
  985. );
  986. }
  987. parts.push(" ", path.call(print, "body"));
  988. return concat(parts);
  989. case "TemplateElement":
  990. return fromString(n.value.raw, options).lockIndentTail();
  991. case "TemplateLiteral":
  992. var expressions = path.map(print, "expressions");
  993. parts.push("`");
  994. path.each(function(childPath) {
  995. var i = childPath.getName();
  996. parts.push(print(childPath));
  997. if (i < expressions.length) {
  998. parts.push("${", expressions[i], "}");
  999. }
  1000. }, "quasis");
  1001. parts.push("`");
  1002. return concat(parts).lockIndentTail();
  1003. case "TaggedTemplateExpression":
  1004. return concat([
  1005. path.call(print, "tag"),
  1006. path.call(print, "quasi")
  1007. ]);
  1008. // These types are unprintable because they serve as abstract
  1009. // supertypes for other (printable) types.
  1010. case "Node":
  1011. case "Printable":
  1012. case "SourceLocation":
  1013. case "Position":
  1014. case "Statement":
  1015. case "Function":
  1016. case "Pattern":
  1017. case "Expression":
  1018. case "Declaration":
  1019. case "Specifier":
  1020. case "NamedSpecifier":
  1021. case "Comment": // Supertype of Block and Line.
  1022. case "MemberTypeAnnotation": // Flow
  1023. case "TupleTypeAnnotation": // Flow
  1024. case "Type": // Flow
  1025. throw new Error("unprintable type: " + JSON.stringify(n.type));
  1026. case "CommentBlock": // Babel block comment.
  1027. case "Block": // Esprima block comment.
  1028. return concat(["/*", fromString(n.value, options), "*/"]);
  1029. case "CommentLine": // Babel line comment.
  1030. case "Line": // Esprima line comment.
  1031. return concat(["//", fromString(n.value, options)]);
  1032. // Type Annotations for Facebook Flow, typically stripped out or
  1033. // transformed away before printing.
  1034. case "TypeAnnotation":
  1035. if (n.typeAnnotation) {
  1036. if (n.typeAnnotation.type !== "FunctionTypeAnnotation") {
  1037. parts.push(": ");
  1038. }
  1039. parts.push(path.call(print, "typeAnnotation"));
  1040. return concat(parts);
  1041. }
  1042. return fromString("");
  1043. case "ExistentialTypeParam":
  1044. case "ExistsTypeAnnotation":
  1045. return fromString("*", options);
  1046. case "EmptyTypeAnnotation":
  1047. return fromString("empty", options);
  1048. case "AnyTypeAnnotation":
  1049. return fromString("any", options);
  1050. case "MixedTypeAnnotation":
  1051. return fromString("mixed", options);
  1052. case "ArrayTypeAnnotation":
  1053. return concat([
  1054. path.call(print, "elementType"),
  1055. "[]"
  1056. ]);
  1057. case "BooleanTypeAnnotation":
  1058. return fromString("boolean", options);
  1059. case "BooleanLiteralTypeAnnotation":
  1060. assert.strictEqual(typeof n.value, "boolean");
  1061. return fromString("" + n.value, options);
  1062. case "DeclareClass":
  1063. return printFlowDeclaration(path, [
  1064. "class ",
  1065. path.call(print, "id"),
  1066. " ",
  1067. path.call(print, "body"),
  1068. ]);
  1069. case "DeclareFunction":
  1070. return printFlowDeclaration(path, [
  1071. "function ",
  1072. path.call(print, "id"),
  1073. ";"
  1074. ]);
  1075. case "DeclareModule":
  1076. return printFlowDeclaration(path, [
  1077. "module ",
  1078. path.call(print, "id"),
  1079. " ",
  1080. path.call(print, "body"),
  1081. ]);
  1082. case "DeclareModuleExports":
  1083. return printFlowDeclaration(path, [
  1084. "module.exports",
  1085. path.call(print, "typeAnnotation"),
  1086. ]);
  1087. case "DeclareVariable":
  1088. return printFlowDeclaration(path, [
  1089. "var ",
  1090. path.call(print, "id"),
  1091. ";"
  1092. ]);
  1093. case "DeclareExportDeclaration":
  1094. case "DeclareExportAllDeclaration":
  1095. return concat([
  1096. "declare ",
  1097. printExportDeclaration(path, options, print)
  1098. ]);
  1099. case "FunctionTypeAnnotation":
  1100. // FunctionTypeAnnotation is ambiguous:
  1101. // declare function(a: B): void; OR
  1102. // var A: (a: B) => void;
  1103. var parent = path.getParentNode(0);
  1104. var isArrowFunctionTypeAnnotation = !(
  1105. namedTypes.ObjectTypeCallProperty.check(parent) ||
  1106. namedTypes.DeclareFunction.check(path.getParentNode(2))
  1107. );
  1108. var needsColon =
  1109. isArrowFunctionTypeAnnotation &&
  1110. !namedTypes.FunctionTypeParam.check(parent);
  1111. if (needsColon) {
  1112. parts.push(": ");
  1113. }
  1114. parts.push(
  1115. "(",
  1116. fromString(", ").join(path.map(print, "params")),
  1117. ")"
  1118. );
  1119. // The returnType is not wrapped in a TypeAnnotation, so the colon
  1120. // needs to be added separately.
  1121. if (n.returnType) {
  1122. parts.push(
  1123. isArrowFunctionTypeAnnotation ? " => " : ": ",
  1124. path.call(print, "returnType")
  1125. );
  1126. }
  1127. return concat(parts);
  1128. case "FunctionTypeParam":
  1129. return concat([
  1130. path.call(print, "name"),
  1131. n.optional ? '?' : '',
  1132. ": ",
  1133. path.call(print, "typeAnnotation"),
  1134. ]);
  1135. case "GenericTypeAnnotation":
  1136. return concat([
  1137. path.call(print, "id"),
  1138. path.call(print, "typeParameters")
  1139. ]);
  1140. case "DeclareInterface":
  1141. parts.push("declare ");
  1142. case "InterfaceDeclaration":
  1143. parts.push(
  1144. fromString("interface ", options),
  1145. path.call(print, "id"),
  1146. path.call(print, "typeParameters"),
  1147. " "
  1148. );
  1149. if (n["extends"]) {
  1150. parts.push(
  1151. "extends ",
  1152. fromString(", ").join(path.map(print, "extends"))
  1153. );
  1154. }
  1155. parts.push(" ", path.call(print, "body"));
  1156. return concat(parts);
  1157. case "ClassImplements":
  1158. case "InterfaceExtends":
  1159. return concat([
  1160. path.call(print, "id"),
  1161. path.call(print, "typeParameters")
  1162. ]);
  1163. case "IntersectionTypeAnnotation":
  1164. return fromString(" & ").join(path.map(print, "types"));
  1165. case "NullableTypeAnnotation":
  1166. return concat([
  1167. "?",
  1168. path.call(print, "typeAnnotation")
  1169. ]);
  1170. case "NullLiteralTypeAnnotation":
  1171. return fromString("null", options);
  1172. case "ThisTypeAnnotation":
  1173. return fromString("this", options);
  1174. case "NumberTypeAnnotation":
  1175. return fromString("number", options);
  1176. case "ObjectTypeCallProperty":
  1177. return path.call(print, "value");
  1178. case "ObjectTypeIndexer":
  1179. var variance =
  1180. n.variance === "plus" ? "+" :
  1181. n.variance === "minus" ? "-" : "";
  1182. return concat([
  1183. variance,
  1184. "[",
  1185. path.call(print, "id"),
  1186. ": ",
  1187. path.call(print, "key"),
  1188. "]: ",
  1189. path.call(print, "value")
  1190. ]);
  1191. case "ObjectTypeProperty":
  1192. var variance =
  1193. n.variance === "plus" ? "+" :
  1194. n.variance === "minus" ? "-" : "";
  1195. return concat([
  1196. variance,
  1197. path.call(print, "key"),
  1198. n.optional ? "?" : "",
  1199. ": ",
  1200. path.call(print, "value")
  1201. ]);
  1202. case "QualifiedTypeIdentifier":
  1203. return concat([
  1204. path.call(print, "qualification"),
  1205. ".",
  1206. path.call(print, "id")
  1207. ]);
  1208. case "StringLiteralTypeAnnotation":
  1209. return fromString(nodeStr(n.value, options), options);
  1210. case "NumberLiteralTypeAnnotation":
  1211. case "NumericLiteralTypeAnnotation":
  1212. assert.strictEqual(typeof n.value, "number");
  1213. return fromString(JSON.stringify(n.value), options);
  1214. case "StringTypeAnnotation":
  1215. return fromString("string", options);
  1216. case "DeclareTypeAlias":
  1217. parts.push("declare ");
  1218. case "TypeAlias":
  1219. return concat([
  1220. "type ",
  1221. path.call(print, "id"),
  1222. path.call(print, "typeParameters"),
  1223. " = ",
  1224. path.call(print, "right"),
  1225. ";"
  1226. ]);
  1227. case "TypeCastExpression":
  1228. return concat([
  1229. "(",
  1230. path.call(print, "expression"),
  1231. path.call(print, "typeAnnotation"),
  1232. ")"
  1233. ]);
  1234. case "TypeParameterDeclaration":
  1235. case "TypeParameterInstantiation":
  1236. return concat([
  1237. "<",
  1238. fromString(", ").join(path.map(print, "params")),
  1239. ">"
  1240. ]);
  1241. case "TypeParameter":
  1242. switch (n.variance) {
  1243. case 'plus':
  1244. parts.push('+');
  1245. break;
  1246. case 'minus':
  1247. parts.push('-');
  1248. break;
  1249. default:
  1250. }
  1251. parts.push(path.call(print, 'name'));
  1252. if (n.bound) {
  1253. parts.push(path.call(print, 'bound'));
  1254. }
  1255. if (n['default']) {
  1256. parts.push('=', path.call(print, 'default'));
  1257. }
  1258. return concat(parts);
  1259. case "TypeofTypeAnnotation":
  1260. return concat([
  1261. fromString("typeof ", options),
  1262. path.call(print, "argument")
  1263. ]);
  1264. case "UnionTypeAnnotation":
  1265. return fromString(" | ").join(path.map(print, "types"));
  1266. case "VoidTypeAnnotation":
  1267. return fromString("void", options);
  1268. case "NullTypeAnnotation":
  1269. return fromString("null", options);
  1270. // Unhandled types below. If encountered, nodes of these types should
  1271. // be either left alone or desugared into AST types that are fully
  1272. // supported by the pretty-printer.
  1273. case "ClassHeritage": // TODO
  1274. case "ComprehensionBlock": // TODO
  1275. case "ComprehensionExpression": // TODO
  1276. case "Glob": // TODO
  1277. case "GeneratorExpression": // TODO
  1278. case "LetStatement": // TODO
  1279. case "LetExpression": // TODO
  1280. case "GraphExpression": // TODO
  1281. case "GraphIndexExpression": // TODO
  1282. // XML types that nobody cares about or needs to print.
  1283. case "XMLDefaultDeclaration":
  1284. case "XMLAnyName":
  1285. case "XMLQualifiedIdentifier":
  1286. case "XMLFunctionQualifiedIdentifier":
  1287. case "XMLAttributeSelector":
  1288. case "XMLFilterExpression":
  1289. case "XML":
  1290. case "XMLElement":
  1291. case "XMLList":
  1292. case "XMLEscape":
  1293. case "XMLText":
  1294. case "XMLStartTag":
  1295. case "XMLEndTag":
  1296. case "XMLPointTag":
  1297. case "XMLName":
  1298. case "XMLAttribute":
  1299. case "XMLCdata":
  1300. case "XMLComment":
  1301. case "XMLProcessingInstruction":
  1302. default:
  1303. debugger;
  1304. throw new Error("unknown type: " + JSON.stringify(n.type));
  1305. }
  1306. return p;
  1307. }
  1308. function printStatementSequence(path, options, print) {
  1309. var inClassBody =
  1310. namedTypes.ClassBody &&
  1311. namedTypes.ClassBody.check(path.getParentNode());
  1312. var filtered = [];
  1313. var sawComment = false;
  1314. var sawStatement = false;
  1315. path.each(function(stmtPath) {
  1316. var i = stmtPath.getName();
  1317. var stmt = stmtPath.getValue();
  1318. // Just in case the AST has been modified to contain falsy
  1319. // "statements," it's safer simply to skip them.
  1320. if (!stmt) {
  1321. return;
  1322. }
  1323. // Skip printing EmptyStatement nodes to avoid leaving stray
  1324. // semicolons lying around.
  1325. if (stmt.type === "EmptyStatement") {
  1326. return;
  1327. }
  1328. if (namedTypes.Comment.check(stmt)) {
  1329. // The pretty printer allows a dangling Comment node to act as
  1330. // a Statement when the Comment can't be attached to any other
  1331. // non-Comment node in the tree.
  1332. sawComment = true;
  1333. } else if (namedTypes.Statement.check(stmt)) {
  1334. sawStatement = true;
  1335. } else {
  1336. // When the pretty printer encounters a string instead of an
  1337. // AST node, it just prints the string. This behavior can be
  1338. // useful for fine-grained formatting decisions like inserting
  1339. // blank lines.
  1340. isString.assert(stmt);
  1341. }
  1342. // We can't hang onto stmtPath outside of this function, because
  1343. // it's just a reference to a mutable FastPath object, so we have
  1344. // to go ahead and print it here.
  1345. filtered.push({
  1346. node: stmt,
  1347. printed: print(stmtPath)
  1348. });
  1349. });
  1350. if (sawComment) {
  1351. assert.strictEqual(
  1352. sawStatement, false,
  1353. "Comments may appear as statements in otherwise empty statement " +
  1354. "lists, but may not coexist with non-Comment nodes."
  1355. );
  1356. }
  1357. var prevTrailingSpace = null;
  1358. var len = filtered.length;
  1359. var parts = [];
  1360. filtered.forEach(function(info, i) {
  1361. var printed = info.printed;
  1362. var stmt = info.node;
  1363. var multiLine = printed.length > 1;
  1364. var notFirst = i > 0;
  1365. var notLast = i < len - 1;
  1366. var leadingSpace;
  1367. var trailingSpace;
  1368. var lines = stmt && stmt.loc && stmt.loc.lines;
  1369. var trueLoc = lines && options.reuseWhitespace &&
  1370. util.getTrueLoc(stmt, lines);
  1371. if (notFirst) {
  1372. if (trueLoc) {
  1373. var beforeStart = lines.skipSpaces(trueLoc.start, true);
  1374. var beforeStartLine = beforeStart ? beforeStart.line : 1;
  1375. var leadingGap = trueLoc.start.line - beforeStartLine;
  1376. leadingSpace = Array(leadingGap + 1).join("\n");
  1377. } else {
  1378. leadingSpace = multiLine ? "\n\n" : "\n";
  1379. }
  1380. } else {
  1381. leadingSpace = "";
  1382. }
  1383. if (notLast) {
  1384. if (trueLoc) {
  1385. var afterEnd = lines.skipSpaces(trueLoc.end);
  1386. var afterEndLine = afterEnd ? afterEnd.line : lines.length;
  1387. var trailingGap = afterEndLine - trueLoc.end.line;
  1388. trailingSpace = Array(trailingGap + 1).join("\n");
  1389. } else {
  1390. trailingSpace = multiLine ? "\n\n" : "\n";
  1391. }
  1392. } else {
  1393. trailingSpace = "";
  1394. }
  1395. parts.push(
  1396. maxSpace(prevTrailingSpace, leadingSpace),
  1397. printed
  1398. );
  1399. if (notLast) {
  1400. prevTrailingSpace = trailingSpace;
  1401. } else if (trailingSpace) {
  1402. parts.push(trailingSpace);
  1403. }
  1404. });
  1405. return concat(parts);
  1406. }
  1407. function maxSpace(s1, s2) {
  1408. if (!s1 && !s2) {
  1409. return fromString("");
  1410. }
  1411. if (!s1) {
  1412. return fromString(s2);
  1413. }
  1414. if (!s2) {
  1415. return fromString(s1);
  1416. }
  1417. var spaceLines1 = fromString(s1);
  1418. var spaceLines2 = fromString(s2);
  1419. if (spaceLines2.length > spaceLines1.length) {
  1420. return spaceLines2;
  1421. }
  1422. return spaceLines1;
  1423. }
  1424. function printMethod(path, options, print) {
  1425. var node = path.getNode();
  1426. var kind = node.kind;
  1427. var parts = [];
  1428. if (node.type === "ObjectMethod" || node.type === "ClassMethod") {
  1429. node.value = node;
  1430. } else {
  1431. namedTypes.FunctionExpression.assert(node.value);
  1432. }
  1433. if (node.value.async) {
  1434. parts.push("async ");
  1435. }
  1436. if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
  1437. if (node.value.generator) {
  1438. parts.push("*");
  1439. }
  1440. } else {
  1441. assert.ok(kind === "get" || kind === "set");
  1442. parts.push(kind, " ");
  1443. }
  1444. var key = path.call(print, "key");
  1445. if (node.computed) {
  1446. key = concat(["[", key, "]"]);
  1447. }
  1448. parts.push(
  1449. key,
  1450. path.call(print, "value", "typeParameters"),
  1451. "(",
  1452. path.call(function(valuePath) {
  1453. return printFunctionParams(valuePath, options, print);
  1454. }, "value"),
  1455. ")",
  1456. path.call(print, "value", "returnType"),
  1457. " ",
  1458. path.call(print, "value", "body")
  1459. );
  1460. return concat(parts);
  1461. }
  1462. function printArgumentsList(path, options, print) {
  1463. var printed = path.map(print, "arguments");
  1464. var trailingComma = util.isTrailingCommaEnabled(options, "parameters");
  1465. var joined = fromString(", ").join(printed);
  1466. if (joined.getLineLength(1) > options.wrapColumn) {
  1467. joined = fromString(",\n").join(printed);
  1468. return concat([
  1469. "(\n",
  1470. joined.indent(options.tabWidth),
  1471. trailingComma ? ",\n)" : "\n)"
  1472. ]);
  1473. }
  1474. return concat(["(", joined, ")"]);
  1475. }
  1476. function printFunctionParams(path, options, print) {
  1477. var fun = path.getValue();
  1478. namedTypes.Function.assert(fun);
  1479. var printed = path.map(print, "params");
  1480. if (fun.defaults) {
  1481. path.each(function(defExprPath) {
  1482. var i = defExprPath.getName();
  1483. var p = printed[i];
  1484. if (p && defExprPath.getValue()) {
  1485. printed[i] = concat([p, " = ", print(defExprPath)]);
  1486. }
  1487. }, "defaults");
  1488. }
  1489. if (fun.rest) {
  1490. printed.push(concat(["...", path.call(print, "rest")]));
  1491. }
  1492. var joined = fromString(", ").join(printed);
  1493. if (joined.length > 1 ||
  1494. joined.getLineLength(1) > options.wrapColumn) {
  1495. joined = fromString(",\n").join(printed);
  1496. if (util.isTrailingCommaEnabled(options, "parameters") &&
  1497. !fun.rest &&
  1498. fun.params[fun.params.length - 1].type !== 'RestElement') {
  1499. joined = concat([joined, ",\n"]);
  1500. } else {
  1501. joined = concat([joined, "\n"]);
  1502. }
  1503. return concat(["\n", joined.indent(options.tabWidth)]);
  1504. }
  1505. return joined;
  1506. }
  1507. function printObjectMethod(path, options, print) {
  1508. var objMethod = path.getValue();
  1509. var parts = [];
  1510. if (objMethod.async)
  1511. parts.push("async ");
  1512. if (objMethod.generator)
  1513. parts.push("*");
  1514. if (objMethod.method || objMethod.kind === "get" || objMethod.kind === "set") {
  1515. return printMethod(path, options, print);
  1516. }
  1517. var key = path.call(print, "key");
  1518. if (objMethod.computed) {
  1519. parts.push("[", key, "]");
  1520. } else {
  1521. parts.push(key);
  1522. }
  1523. parts.push(
  1524. "(",
  1525. printFunctionParams(path, options, print),
  1526. ")",
  1527. path.call(print, "returnType"),
  1528. " ",
  1529. path.call(print, "body")
  1530. );
  1531. return concat(parts);
  1532. }
  1533. function printExportDeclaration(path, options, print) {
  1534. var decl = path.getValue();
  1535. var parts = ["export "];
  1536. var shouldPrintSpaces = options.objectCurlySpacing;
  1537. namedTypes.Declaration.assert(decl);
  1538. if (decl["default"] ||
  1539. decl.type === "ExportDefaultDeclaration") {
  1540. parts.push("default ");
  1541. }
  1542. if (decl.declaration) {
  1543. parts.push(path.call(print, "declaration"));
  1544. } else if (decl.specifiers &&
  1545. decl.specifiers.length > 0) {
  1546. if (decl.specifiers.length === 1 &&
  1547. decl.specifiers[0].type === "ExportBatchSpecifier") {
  1548. parts.push("*");
  1549. } else {
  1550. parts.push(
  1551. shouldPrintSpaces ? "{ " : "{",
  1552. fromString(", ").join(path.map(print, "specifiers")),
  1553. shouldPrintSpaces ? " }" : "}"
  1554. );
  1555. }
  1556. if (decl.source) {
  1557. parts.push(" from ", path.call(print, "source"));
  1558. }
  1559. }
  1560. var lines = concat(parts);
  1561. if (lastNonSpaceCharacter(lines) !== ";" &&
  1562. ! (decl.declaration &&
  1563. (decl.declaration.type === "FunctionDeclaration" ||
  1564. decl.declaration.type === "ClassDeclaration"))) {
  1565. lines = concat([lines, ";"]);
  1566. }
  1567. return lines;
  1568. }
  1569. function printFlowDeclaration(path, parts) {
  1570. var parentExportDecl = util.getParentExportDeclaration(path);
  1571. if (parentExportDecl) {
  1572. assert.strictEqual(
  1573. parentExportDecl.type,
  1574. "DeclareExportDeclaration"
  1575. );
  1576. } else {
  1577. // If the parent node has type DeclareExportDeclaration, then it
  1578. // will be responsible for printing the "declare" token. Otherwise
  1579. // it needs to be printed with this non-exported declaration node.
  1580. parts.unshift("declare ");
  1581. }
  1582. return concat(parts);
  1583. }
  1584. function adjustClause(clause, options) {
  1585. if (clause.length > 1)
  1586. return concat([" ", clause]);
  1587. return concat([
  1588. "\n",
  1589. maybeAddSemicolon(clause).indent(options.tabWidth)
  1590. ]);
  1591. }
  1592. function lastNonSpaceCharacter(lines) {
  1593. var pos = lines.lastPos();
  1594. do {
  1595. var ch = lines.charAt(pos);
  1596. if (/\S/.test(ch))
  1597. return ch;
  1598. } while (lines.prevPos(pos));
  1599. }
  1600. function endsWithBrace(lines) {
  1601. return lastNonSpaceCharacter(lines) === "}";
  1602. }
  1603. function swapQuotes(str) {
  1604. return str.replace(/['"]/g, function(m) {
  1605. return m === '"' ? '\'' : '"';
  1606. });
  1607. }
  1608. function nodeStr(str, options) {
  1609. isString.assert(str);
  1610. switch (options.quote) {
  1611. case "auto":
  1612. var double = JSON.stringify(str);
  1613. var single = swapQuotes(JSON.stringify(swapQuotes(str)));
  1614. return double.length > single.length ? single : double;
  1615. case "single":
  1616. return swapQuotes(JSON.stringify(swapQuotes(str)));
  1617. case "double":
  1618. default:
  1619. return JSON.stringify(str);
  1620. }
  1621. }
  1622. function maybeAddSemicolon(lines) {
  1623. var eoc = lastNonSpaceCharacter(lines);
  1624. if (!eoc || "\n};".indexOf(eoc) < 0)
  1625. return concat([lines, ";"]);
  1626. return lines;
  1627. }