output.js 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528
  1. /***********************************************************************
  2. A JavaScript tokenizer / parser / beautifier / compressor.
  3. https://github.com/mishoo/UglifyJS2
  4. -------------------------------- (C) ---------------------------------
  5. Author: Mihai Bazon
  6. <mihai.bazon@gmail.com>
  7. http://mihai.bazon.net/blog
  8. Distributed under the BSD license:
  9. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. * Redistributions of source code must retain the above
  14. copyright notice, this list of conditions and the following
  15. disclaimer.
  16. * Redistributions in binary form must reproduce the above
  17. copyright notice, this list of conditions and the following
  18. disclaimer in the documentation and/or other materials
  19. provided with the distribution.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
  21. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  24. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  25. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  29. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. SUCH DAMAGE.
  32. ***********************************************************************/
  33. "use strict";
  34. import {
  35. defaults,
  36. makePredicate,
  37. noop,
  38. regexp_source_fix,
  39. sort_regexp_flags,
  40. return_false,
  41. return_true,
  42. } from "./utils/index.js";
  43. import { first_in_statement, left_is_object } from "./utils/first_in_statement.js";
  44. import {
  45. AST_Array,
  46. AST_Arrow,
  47. AST_Assign,
  48. AST_Await,
  49. AST_BigInt,
  50. AST_Binary,
  51. AST_BlockStatement,
  52. AST_Break,
  53. AST_Call,
  54. AST_Case,
  55. AST_Catch,
  56. AST_Chain,
  57. AST_Class,
  58. AST_ClassExpression,
  59. AST_ClassPrivateProperty,
  60. AST_ClassProperty,
  61. AST_ClassStaticBlock,
  62. AST_ConciseMethod,
  63. AST_PrivateGetter,
  64. AST_PrivateMethod,
  65. AST_SymbolPrivateProperty,
  66. AST_PrivateSetter,
  67. AST_PrivateIn,
  68. AST_Conditional,
  69. AST_Const,
  70. AST_Constant,
  71. AST_Continue,
  72. AST_Debugger,
  73. AST_Default,
  74. AST_DefaultAssign,
  75. AST_Definitions,
  76. AST_Defun,
  77. AST_Destructuring,
  78. AST_Directive,
  79. AST_Do,
  80. AST_Dot,
  81. AST_DotHash,
  82. AST_EmptyStatement,
  83. AST_Exit,
  84. AST_Expansion,
  85. AST_Export,
  86. AST_Finally,
  87. AST_For,
  88. AST_ForIn,
  89. AST_ForOf,
  90. AST_Function,
  91. AST_Hole,
  92. AST_If,
  93. AST_Import,
  94. AST_ImportMeta,
  95. AST_Jump,
  96. AST_LabeledStatement,
  97. AST_Lambda,
  98. AST_Let,
  99. AST_LoopControl,
  100. AST_NameMapping,
  101. AST_New,
  102. AST_NewTarget,
  103. AST_Node,
  104. AST_Number,
  105. AST_Object,
  106. AST_ObjectGetter,
  107. AST_ObjectKeyVal,
  108. AST_ObjectProperty,
  109. AST_ObjectSetter,
  110. AST_PrefixedTemplateString,
  111. AST_PropAccess,
  112. AST_RegExp,
  113. AST_Return,
  114. AST_Scope,
  115. AST_Sequence,
  116. AST_SimpleStatement,
  117. AST_Statement,
  118. AST_StatementWithBody,
  119. AST_String,
  120. AST_Sub,
  121. AST_Super,
  122. AST_Switch,
  123. AST_SwitchBranch,
  124. AST_Symbol,
  125. AST_SymbolClassProperty,
  126. AST_SymbolMethod,
  127. AST_SymbolRef,
  128. AST_TemplateSegment,
  129. AST_TemplateString,
  130. AST_This,
  131. AST_Throw,
  132. AST_Toplevel,
  133. AST_Try,
  134. AST_TryBlock,
  135. AST_Unary,
  136. AST_UnaryPostfix,
  137. AST_UnaryPrefix,
  138. AST_Var,
  139. AST_VarDef,
  140. AST_While,
  141. AST_With,
  142. AST_Yield,
  143. TreeWalker,
  144. walk,
  145. walk_abort
  146. } from "./ast.js";
  147. import {
  148. get_full_char_code,
  149. get_full_char,
  150. is_identifier_char,
  151. is_basic_identifier_string,
  152. is_identifier_string,
  153. PRECEDENCE,
  154. ALL_RESERVED_WORDS,
  155. } from "./parse.js";
  156. const CODE_LINE_BREAK = 10;
  157. const CODE_SPACE = 32;
  158. const r_annotation = /[@#]__(PURE|INLINE|NOINLINE)__/;
  159. function is_some_comments(comment) {
  160. // multiline comment
  161. return (
  162. (comment.type === "comment2" || comment.type === "comment1")
  163. && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value)
  164. );
  165. }
  166. const ROPE_COMMIT_WHEN = 8 * 1000;
  167. class Rope {
  168. constructor() {
  169. this.committed = "";
  170. this.current = "";
  171. }
  172. append(str) {
  173. /** When `this.current` is too long, commit it. */
  174. if (this.current.length > ROPE_COMMIT_WHEN) {
  175. this.committed += this.current + str;
  176. this.current = "";
  177. } else {
  178. this.current += str;
  179. }
  180. }
  181. insertAt(char, index) {
  182. const { committed, current } = this;
  183. if (index < committed.length) {
  184. this.committed = committed.slice(0, index) + char + committed.slice(index);
  185. } else if (index === committed.length) {
  186. this.committed += char;
  187. } else {
  188. index -= committed.length;
  189. this.committed += current.slice(0, index) + char;
  190. this.current = current.slice(index);
  191. }
  192. }
  193. charAt(index) {
  194. const { committed } = this;
  195. if (index < committed.length) return committed[index];
  196. return this.current[index - committed.length];
  197. }
  198. charCodeAt(index) {
  199. const { committed } = this;
  200. if (index < committed.length) return committed.charCodeAt(index);
  201. return this.current.charCodeAt(index - committed.length);
  202. }
  203. length() {
  204. return this.committed.length + this.current.length;
  205. }
  206. expectDirective() {
  207. // /^$|[;{][\s\n]*$/
  208. let ch, n = this.length();
  209. if (n <= 0) return true;
  210. // Skip N whitespace from the end
  211. while (
  212. (ch = this.charCodeAt(--n))
  213. && (ch == CODE_SPACE || ch == CODE_LINE_BREAK)
  214. );
  215. // either ";", or "{", or the string ended
  216. return !ch || ch === 59 || ch === 123;
  217. }
  218. hasNLB() {
  219. let n = this.length() - 1;
  220. while (n >= 0) {
  221. const code = this.charCodeAt(n--);
  222. if (code === CODE_LINE_BREAK) return true;
  223. if (code !== CODE_SPACE) return false;
  224. }
  225. return true;
  226. }
  227. toString() {
  228. return this.committed + this.current;
  229. }
  230. }
  231. function OutputStream(options) {
  232. var readonly = !options;
  233. options = defaults(options, {
  234. ascii_only : false,
  235. beautify : false,
  236. braces : false,
  237. comments : "some",
  238. ecma : 5,
  239. ie8 : false,
  240. indent_level : 4,
  241. indent_start : 0,
  242. inline_script : true,
  243. keep_numbers : false,
  244. keep_quoted_props : false,
  245. max_line_len : false,
  246. preamble : null,
  247. preserve_annotations : false,
  248. quote_keys : false,
  249. quote_style : 0,
  250. safari10 : false,
  251. semicolons : true,
  252. shebang : true,
  253. shorthand : undefined,
  254. source_map : null,
  255. webkit : false,
  256. width : 80,
  257. wrap_iife : false,
  258. wrap_func_args : true,
  259. _destroy_ast : false
  260. }, true);
  261. if (options.shorthand === undefined)
  262. options.shorthand = options.ecma > 5;
  263. // Convert comment option to RegExp if necessary and set up comments filter
  264. var comment_filter = return_false; // Default case, throw all comments away
  265. if (options.comments) {
  266. let comments = options.comments;
  267. if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
  268. var regex_pos = options.comments.lastIndexOf("/");
  269. comments = new RegExp(
  270. options.comments.substr(1, regex_pos - 1),
  271. options.comments.substr(regex_pos + 1)
  272. );
  273. }
  274. if (comments instanceof RegExp) {
  275. comment_filter = function(comment) {
  276. return comment.type != "comment5" && comments.test(comment.value);
  277. };
  278. } else if (typeof comments === "function") {
  279. comment_filter = function(comment) {
  280. return comment.type != "comment5" && comments(this, comment);
  281. };
  282. } else if (comments === "some") {
  283. comment_filter = is_some_comments;
  284. } else { // NOTE includes "all" option
  285. comment_filter = return_true;
  286. }
  287. }
  288. if (options.preserve_annotations) {
  289. let prev_comment_filter = comment_filter;
  290. comment_filter = function (comment) {
  291. return r_annotation.test(comment.value) || prev_comment_filter.apply(this, arguments);
  292. };
  293. }
  294. var indentation = 0;
  295. var current_col = 0;
  296. var current_line = 1;
  297. var current_pos = 0;
  298. var OUTPUT = new Rope();
  299. let printed_comments = new Set();
  300. var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) {
  301. if (options.ecma >= 2015 && !options.safari10 && !regexp) {
  302. str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
  303. var code = get_full_char_code(ch, 0).toString(16);
  304. return "\\u{" + code + "}";
  305. });
  306. }
  307. return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
  308. var code = ch.charCodeAt(0).toString(16);
  309. if (code.length <= 2 && !identifier) {
  310. while (code.length < 2) code = "0" + code;
  311. return "\\x" + code;
  312. } else {
  313. while (code.length < 4) code = "0" + code;
  314. return "\\u" + code;
  315. }
  316. });
  317. } : function(str) {
  318. return str.replace(/[\ud800-\udbff][\udc00-\udfff]|([\ud800-\udbff]|[\udc00-\udfff])/g, function(match, lone) {
  319. if (lone) {
  320. return "\\u" + lone.charCodeAt(0).toString(16);
  321. }
  322. return match;
  323. });
  324. };
  325. function make_string(str, quote) {
  326. var dq = 0, sq = 0;
  327. str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
  328. function(s, i) {
  329. switch (s) {
  330. case '"': ++dq; return '"';
  331. case "'": ++sq; return "'";
  332. case "\\": return "\\\\";
  333. case "\n": return "\\n";
  334. case "\r": return "\\r";
  335. case "\t": return "\\t";
  336. case "\b": return "\\b";
  337. case "\f": return "\\f";
  338. case "\x0B": return options.ie8 ? "\\x0B" : "\\v";
  339. case "\u2028": return "\\u2028";
  340. case "\u2029": return "\\u2029";
  341. case "\ufeff": return "\\ufeff";
  342. case "\0":
  343. return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
  344. }
  345. return s;
  346. });
  347. function quote_single() {
  348. return "'" + str.replace(/\x27/g, "\\'") + "'";
  349. }
  350. function quote_double() {
  351. return '"' + str.replace(/\x22/g, '\\"') + '"';
  352. }
  353. function quote_template() {
  354. return "`" + str.replace(/`/g, "\\`") + "`";
  355. }
  356. str = to_utf8(str);
  357. if (quote === "`") return quote_template();
  358. switch (options.quote_style) {
  359. case 1:
  360. return quote_single();
  361. case 2:
  362. return quote_double();
  363. case 3:
  364. return quote == "'" ? quote_single() : quote_double();
  365. default:
  366. return dq > sq ? quote_single() : quote_double();
  367. }
  368. }
  369. function encode_string(str, quote) {
  370. var ret = make_string(str, quote);
  371. if (options.inline_script) {
  372. ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
  373. ret = ret.replace(/\x3c!--/g, "\\x3c!--");
  374. ret = ret.replace(/--\x3e/g, "--\\x3e");
  375. }
  376. return ret;
  377. }
  378. function make_name(name) {
  379. name = name.toString();
  380. name = to_utf8(name, true);
  381. return name;
  382. }
  383. function make_indent(back) {
  384. return " ".repeat(options.indent_start + indentation - back * options.indent_level);
  385. }
  386. /* -----[ beautification/minification ]----- */
  387. var has_parens = false;
  388. var might_need_space = false;
  389. var might_need_semicolon = false;
  390. var might_add_newline = 0;
  391. var need_newline_indented = false;
  392. var need_space = false;
  393. var newline_insert = -1;
  394. var last = "";
  395. var mapping_token, mapping_name, mappings = options.source_map && [];
  396. var do_add_mapping = mappings ? function() {
  397. mappings.forEach(function(mapping) {
  398. try {
  399. let { name, token } = mapping;
  400. if (name !== false) {
  401. if (token.type == "name" || token.type === "privatename") {
  402. name = token.value;
  403. } else if (name instanceof AST_Symbol) {
  404. name = token.type === "string" ? token.value : name.name;
  405. }
  406. }
  407. options.source_map.add(
  408. mapping.token.file,
  409. mapping.line, mapping.col,
  410. mapping.token.line, mapping.token.col,
  411. is_basic_identifier_string(name) ? name : undefined
  412. );
  413. } catch(ex) {
  414. // Ignore bad mapping
  415. }
  416. });
  417. mappings = [];
  418. } : noop;
  419. var ensure_line_len = options.max_line_len ? function() {
  420. if (current_col > options.max_line_len) {
  421. if (might_add_newline) {
  422. OUTPUT.insertAt("\n", might_add_newline);
  423. const len_after_newline = OUTPUT.length() - might_add_newline - 1;
  424. if (mappings) {
  425. var delta = len_after_newline - current_col;
  426. mappings.forEach(function(mapping) {
  427. mapping.line++;
  428. mapping.col += delta;
  429. });
  430. }
  431. current_line++;
  432. current_pos++;
  433. current_col = len_after_newline;
  434. }
  435. }
  436. if (might_add_newline) {
  437. might_add_newline = 0;
  438. do_add_mapping();
  439. }
  440. } : noop;
  441. var requireSemicolonChars = makePredicate("( [ + * / - , . `");
  442. function print(str) {
  443. str = String(str);
  444. var ch = get_full_char(str, 0);
  445. if (need_newline_indented && ch) {
  446. need_newline_indented = false;
  447. if (ch !== "\n") {
  448. print("\n");
  449. indent();
  450. }
  451. }
  452. if (need_space && ch) {
  453. need_space = false;
  454. if (!/[\s;})]/.test(ch)) {
  455. space();
  456. }
  457. }
  458. newline_insert = -1;
  459. var prev = last.charAt(last.length - 1);
  460. if (might_need_semicolon) {
  461. might_need_semicolon = false;
  462. if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") {
  463. if (options.semicolons || requireSemicolonChars.has(ch)) {
  464. OUTPUT.append(";");
  465. current_col++;
  466. current_pos++;
  467. } else {
  468. ensure_line_len();
  469. if (current_col > 0) {
  470. OUTPUT.append("\n");
  471. current_pos++;
  472. current_line++;
  473. current_col = 0;
  474. }
  475. if (/^\s+$/.test(str)) {
  476. // reset the semicolon flag, since we didn't print one
  477. // now and might still have to later
  478. might_need_semicolon = true;
  479. }
  480. }
  481. if (!options.beautify)
  482. might_need_space = false;
  483. }
  484. }
  485. if (might_need_space) {
  486. if ((is_identifier_char(prev)
  487. && (is_identifier_char(ch) || ch == "\\"))
  488. || (ch == "/" && ch == prev)
  489. || ((ch == "+" || ch == "-") && ch == last)
  490. ) {
  491. OUTPUT.append(" ");
  492. current_col++;
  493. current_pos++;
  494. }
  495. might_need_space = false;
  496. }
  497. if (mapping_token) {
  498. mappings.push({
  499. token: mapping_token,
  500. name: mapping_name,
  501. line: current_line,
  502. col: current_col
  503. });
  504. mapping_token = false;
  505. if (!might_add_newline) do_add_mapping();
  506. }
  507. OUTPUT.append(str);
  508. has_parens = str[str.length - 1] == "(";
  509. current_pos += str.length;
  510. var a = str.split(/\r?\n/), n = a.length - 1;
  511. current_line += n;
  512. current_col += a[0].length;
  513. if (n > 0) {
  514. ensure_line_len();
  515. current_col = a[n].length;
  516. }
  517. last = str;
  518. }
  519. var star = function() {
  520. print("*");
  521. };
  522. var space = options.beautify ? function() {
  523. print(" ");
  524. } : function() {
  525. might_need_space = true;
  526. };
  527. var indent = options.beautify ? function(half) {
  528. if (options.beautify) {
  529. print(make_indent(half ? 0.5 : 0));
  530. }
  531. } : noop;
  532. var with_indent = options.beautify ? function(col, cont) {
  533. if (col === true) col = next_indent();
  534. var save_indentation = indentation;
  535. indentation = col;
  536. var ret = cont();
  537. indentation = save_indentation;
  538. return ret;
  539. } : function(col, cont) { return cont(); };
  540. var newline = options.beautify ? function() {
  541. if (newline_insert < 0) return print("\n");
  542. if (OUTPUT.charAt(newline_insert) != "\n") {
  543. OUTPUT.insertAt("\n", newline_insert);
  544. current_pos++;
  545. current_line++;
  546. }
  547. newline_insert++;
  548. } : options.max_line_len ? function() {
  549. ensure_line_len();
  550. might_add_newline = OUTPUT.length();
  551. } : noop;
  552. var semicolon = options.beautify ? function() {
  553. print(";");
  554. } : function() {
  555. might_need_semicolon = true;
  556. };
  557. function force_semicolon() {
  558. might_need_semicolon = false;
  559. print(";");
  560. }
  561. function next_indent() {
  562. return indentation + options.indent_level;
  563. }
  564. function with_block(cont) {
  565. var ret;
  566. print("{");
  567. newline();
  568. with_indent(next_indent(), function() {
  569. ret = cont();
  570. });
  571. indent();
  572. print("}");
  573. return ret;
  574. }
  575. function with_parens(cont) {
  576. print("(");
  577. //XXX: still nice to have that for argument lists
  578. //var ret = with_indent(current_col, cont);
  579. var ret = cont();
  580. print(")");
  581. return ret;
  582. }
  583. function with_square(cont) {
  584. print("[");
  585. //var ret = with_indent(current_col, cont);
  586. var ret = cont();
  587. print("]");
  588. return ret;
  589. }
  590. function comma() {
  591. print(",");
  592. space();
  593. }
  594. function colon() {
  595. print(":");
  596. space();
  597. }
  598. var add_mapping = mappings ? function(token, name) {
  599. mapping_token = token;
  600. mapping_name = name;
  601. } : noop;
  602. function get() {
  603. if (might_add_newline) {
  604. ensure_line_len();
  605. }
  606. return OUTPUT.toString();
  607. }
  608. function filter_comment(comment) {
  609. if (!options.preserve_annotations) {
  610. comment = comment.replace(r_annotation, " ");
  611. }
  612. if (/^\s*$/.test(comment)) {
  613. return "";
  614. }
  615. return comment.replace(/(<\s*\/\s*)(script)/i, "<\\/$2");
  616. }
  617. function prepend_comments(node) {
  618. var self = this;
  619. var start = node.start;
  620. if (!start) return;
  621. var printed_comments = self.printed_comments;
  622. // There cannot be a newline between return/yield and its value.
  623. const keyword_with_value =
  624. node instanceof AST_Exit && node.value
  625. || (node instanceof AST_Await || node instanceof AST_Yield)
  626. && node.expression;
  627. if (
  628. start.comments_before
  629. && printed_comments.has(start.comments_before)
  630. ) {
  631. if (keyword_with_value) {
  632. start.comments_before = [];
  633. } else {
  634. return;
  635. }
  636. }
  637. var comments = start.comments_before;
  638. if (!comments) {
  639. comments = start.comments_before = [];
  640. }
  641. printed_comments.add(comments);
  642. if (keyword_with_value) {
  643. var tw = new TreeWalker(function(node) {
  644. var parent = tw.parent();
  645. if (parent instanceof AST_Exit
  646. || parent instanceof AST_Await
  647. || parent instanceof AST_Yield
  648. || parent instanceof AST_Binary && parent.left === node
  649. || parent.TYPE == "Call" && parent.expression === node
  650. || parent instanceof AST_Conditional && parent.condition === node
  651. || parent instanceof AST_Dot && parent.expression === node
  652. || parent instanceof AST_Sequence && parent.expressions[0] === node
  653. || parent instanceof AST_Sub && parent.expression === node
  654. || parent instanceof AST_UnaryPostfix) {
  655. if (!node.start) return;
  656. var text = node.start.comments_before;
  657. if (text && !printed_comments.has(text)) {
  658. printed_comments.add(text);
  659. comments = comments.concat(text);
  660. }
  661. } else {
  662. return true;
  663. }
  664. });
  665. tw.push(node);
  666. keyword_with_value.walk(tw);
  667. }
  668. if (current_pos == 0) {
  669. if (comments.length > 0 && options.shebang && comments[0].type === "comment5"
  670. && !printed_comments.has(comments[0])) {
  671. print("#!" + comments.shift().value + "\n");
  672. indent();
  673. }
  674. var preamble = options.preamble;
  675. if (preamble) {
  676. print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
  677. }
  678. }
  679. comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c));
  680. if (comments.length == 0) return;
  681. var last_nlb = OUTPUT.hasNLB();
  682. comments.forEach(function(c, i) {
  683. printed_comments.add(c);
  684. if (!last_nlb) {
  685. if (c.nlb) {
  686. print("\n");
  687. indent();
  688. last_nlb = true;
  689. } else if (i > 0) {
  690. space();
  691. }
  692. }
  693. if (/comment[134]/.test(c.type)) {
  694. var value = filter_comment(c.value);
  695. if (value) {
  696. print("//" + value + "\n");
  697. indent();
  698. }
  699. last_nlb = true;
  700. } else if (c.type == "comment2") {
  701. var value = filter_comment(c.value);
  702. if (value) {
  703. print("/*" + value + "*/");
  704. }
  705. last_nlb = false;
  706. }
  707. });
  708. if (!last_nlb) {
  709. if (start.nlb) {
  710. print("\n");
  711. indent();
  712. } else {
  713. space();
  714. }
  715. }
  716. }
  717. function append_comments(node, tail) {
  718. var self = this;
  719. var token = node.end;
  720. if (!token) return;
  721. var printed_comments = self.printed_comments;
  722. var comments = token[tail ? "comments_before" : "comments_after"];
  723. if (!comments || printed_comments.has(comments)) return;
  724. if (!(node instanceof AST_Statement || comments.every((c) =>
  725. !/comment[134]/.test(c.type)
  726. ))) return;
  727. printed_comments.add(comments);
  728. var insert = OUTPUT.length();
  729. comments.filter(comment_filter, node).forEach(function(c, i) {
  730. if (printed_comments.has(c)) return;
  731. printed_comments.add(c);
  732. need_space = false;
  733. if (need_newline_indented) {
  734. print("\n");
  735. indent();
  736. need_newline_indented = false;
  737. } else if (c.nlb && (i > 0 || !OUTPUT.hasNLB())) {
  738. print("\n");
  739. indent();
  740. } else if (i > 0 || !tail) {
  741. space();
  742. }
  743. if (/comment[134]/.test(c.type)) {
  744. const value = filter_comment(c.value);
  745. if (value) {
  746. print("//" + value);
  747. }
  748. need_newline_indented = true;
  749. } else if (c.type == "comment2") {
  750. const value = filter_comment(c.value);
  751. if (value) {
  752. print("/*" + value + "*/");
  753. }
  754. need_space = true;
  755. }
  756. });
  757. if (OUTPUT.length() > insert) newline_insert = insert;
  758. }
  759. /**
  760. * When output.option("_destroy_ast") is enabled, destroy the function.
  761. * Call this after printing it.
  762. */
  763. const gc_scope =
  764. options["_destroy_ast"]
  765. ? function gc_scope(scope) {
  766. scope.body.length = 0;
  767. scope.argnames.length = 0;
  768. }
  769. : noop;
  770. var stack = [];
  771. return {
  772. get : get,
  773. toString : get,
  774. indent : indent,
  775. in_directive : false,
  776. use_asm : null,
  777. active_scope : null,
  778. indentation : function() { return indentation; },
  779. current_width : function() { return current_col - indentation; },
  780. should_break : function() { return options.width && this.current_width() >= options.width; },
  781. has_parens : function() { return has_parens; },
  782. newline : newline,
  783. print : print,
  784. star : star,
  785. space : space,
  786. comma : comma,
  787. colon : colon,
  788. last : function() { return last; },
  789. semicolon : semicolon,
  790. force_semicolon : force_semicolon,
  791. to_utf8 : to_utf8,
  792. print_name : function(name) { print(make_name(name)); },
  793. print_string : function(str, quote, escape_directive) {
  794. var encoded = encode_string(str, quote);
  795. if (escape_directive === true && !encoded.includes("\\")) {
  796. // Insert semicolons to break directive prologue
  797. if (!OUTPUT.expectDirective()) {
  798. force_semicolon();
  799. }
  800. force_semicolon();
  801. }
  802. print(encoded);
  803. },
  804. print_template_string_chars: function(str) {
  805. var encoded = encode_string(str, "`").replace(/\${/g, "\\${");
  806. return print(encoded.substr(1, encoded.length - 2));
  807. },
  808. encode_string : encode_string,
  809. next_indent : next_indent,
  810. with_indent : with_indent,
  811. with_block : with_block,
  812. with_parens : with_parens,
  813. with_square : with_square,
  814. add_mapping : add_mapping,
  815. option : function(opt) { return options[opt]; },
  816. gc_scope,
  817. printed_comments: printed_comments,
  818. prepend_comments: readonly ? noop : prepend_comments,
  819. append_comments : readonly || comment_filter === return_false ? noop : append_comments,
  820. line : function() { return current_line; },
  821. col : function() { return current_col; },
  822. pos : function() { return current_pos; },
  823. push_node : function(node) { stack.push(node); },
  824. pop_node : function() { return stack.pop(); },
  825. parent : function(n) {
  826. return stack[stack.length - 2 - (n || 0)];
  827. }
  828. };
  829. }
  830. /* -----[ code generators ]----- */
  831. (function() {
  832. /* -----[ utils ]----- */
  833. function DEFPRINT(nodetype, generator) {
  834. nodetype.DEFMETHOD("_codegen", generator);
  835. }
  836. AST_Node.DEFMETHOD("print", function(output, force_parens) {
  837. var self = this, generator = self._codegen;
  838. if (self instanceof AST_Scope) {
  839. output.active_scope = self;
  840. } else if (!output.use_asm && self instanceof AST_Directive && self.value == "use asm") {
  841. output.use_asm = output.active_scope;
  842. }
  843. function doit() {
  844. output.prepend_comments(self);
  845. self.add_source_map(output);
  846. generator(self, output);
  847. output.append_comments(self);
  848. }
  849. output.push_node(self);
  850. if (force_parens || self.needs_parens(output)) {
  851. output.with_parens(doit);
  852. } else {
  853. doit();
  854. }
  855. output.pop_node();
  856. if (self === output.use_asm) {
  857. output.use_asm = null;
  858. }
  859. });
  860. AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
  861. AST_Node.DEFMETHOD("print_to_string", function(options) {
  862. var output = OutputStream(options);
  863. this.print(output);
  864. return output.get();
  865. });
  866. /* -----[ PARENTHESES ]----- */
  867. function PARENS(nodetype, func) {
  868. if (Array.isArray(nodetype)) {
  869. nodetype.forEach(function(nodetype) {
  870. PARENS(nodetype, func);
  871. });
  872. } else {
  873. nodetype.DEFMETHOD("needs_parens", func);
  874. }
  875. }
  876. PARENS(AST_Node, return_false);
  877. // a function expression needs parens around it when it's provably
  878. // the first token to appear in a statement.
  879. PARENS(AST_Function, function(output) {
  880. if (!output.has_parens() && first_in_statement(output)) {
  881. return true;
  882. }
  883. if (output.option("webkit")) {
  884. var p = output.parent();
  885. if (p instanceof AST_PropAccess && p.expression === this) {
  886. return true;
  887. }
  888. }
  889. if (output.option("wrap_iife")) {
  890. var p = output.parent();
  891. if (p instanceof AST_Call && p.expression === this) {
  892. return true;
  893. }
  894. }
  895. if (output.option("wrap_func_args")) {
  896. var p = output.parent();
  897. if (p instanceof AST_Call && p.args.includes(this)) {
  898. return true;
  899. }
  900. }
  901. return false;
  902. });
  903. PARENS(AST_Arrow, function(output) {
  904. var p = output.parent();
  905. if (
  906. output.option("wrap_func_args")
  907. && p instanceof AST_Call
  908. && p.args.includes(this)
  909. ) {
  910. return true;
  911. }
  912. return p instanceof AST_PropAccess && p.expression === this
  913. || p instanceof AST_Conditional && p.condition === this;
  914. });
  915. // same goes for an object literal (as in AST_Function), because
  916. // otherwise {...} would be interpreted as a block of code.
  917. PARENS(AST_Object, function(output) {
  918. return !output.has_parens() && first_in_statement(output);
  919. });
  920. PARENS(AST_ClassExpression, first_in_statement);
  921. PARENS(AST_Unary, function(output) {
  922. var p = output.parent();
  923. return p instanceof AST_PropAccess && p.expression === this
  924. || p instanceof AST_Call && p.expression === this
  925. || p instanceof AST_Binary
  926. && p.operator === "**"
  927. && this instanceof AST_UnaryPrefix
  928. && p.left === this
  929. && this.operator !== "++"
  930. && this.operator !== "--";
  931. });
  932. PARENS(AST_Await, function(output) {
  933. var p = output.parent();
  934. return p instanceof AST_PropAccess && p.expression === this
  935. || p instanceof AST_Call && p.expression === this
  936. || p instanceof AST_Binary && p.operator === "**" && p.left === this
  937. || output.option("safari10") && p instanceof AST_UnaryPrefix;
  938. });
  939. PARENS(AST_Sequence, function(output) {
  940. var p = output.parent();
  941. return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
  942. || p instanceof AST_Unary // !(foo, bar, baz)
  943. || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
  944. || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
  945. || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
  946. || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
  947. || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
  948. || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
  949. * ==> 20 (side effect, set a := 10 and b := 20) */
  950. || p instanceof AST_Arrow // x => (x, x)
  951. || p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
  952. || p instanceof AST_Expansion // [...(a, b)]
  953. || p instanceof AST_ForOf && this === p.object // for (e of (foo, bar)) {}
  954. || p instanceof AST_Yield // yield (foo, bar)
  955. || p instanceof AST_Export // export default (foo, bar)
  956. ;
  957. });
  958. PARENS(AST_Binary, function(output) {
  959. var p = output.parent();
  960. // (foo && bar)()
  961. if (p instanceof AST_Call && p.expression === this)
  962. return true;
  963. // typeof (foo && bar)
  964. if (p instanceof AST_Unary)
  965. return true;
  966. // (foo && bar)["prop"], (foo && bar).prop
  967. if (p instanceof AST_PropAccess && p.expression === this)
  968. return true;
  969. // this deals with precedence: 3 * (2 + 1)
  970. if (p instanceof AST_Binary) {
  971. const parent_op = p.operator;
  972. const op = this.operator;
  973. // It is forbidden for ?? to be used with || or && without parens.
  974. if (op === "??" && (parent_op === "||" || parent_op === "&&")) {
  975. return true;
  976. }
  977. if (parent_op === "??" && (op === "||" || op === "&&")) {
  978. return true;
  979. }
  980. const pp = PRECEDENCE[parent_op];
  981. const sp = PRECEDENCE[op];
  982. if (pp > sp
  983. || (pp == sp
  984. && (this === p.right || parent_op == "**"))) {
  985. return true;
  986. }
  987. }
  988. if (p instanceof AST_PrivateIn) {
  989. const op = this.operator;
  990. const pp = PRECEDENCE["in"];
  991. const sp = PRECEDENCE[op];
  992. if (pp > sp || (pp == sp && this === p.value)) {
  993. return true;
  994. }
  995. }
  996. });
  997. PARENS(AST_PrivateIn, function(output) {
  998. var p = output.parent();
  999. // (#x in this)()
  1000. if (p instanceof AST_Call && p.expression === this) {
  1001. return true;
  1002. }
  1003. // typeof (#x in this)
  1004. if (p instanceof AST_Unary) {
  1005. return true;
  1006. }
  1007. // (#x in this)["prop"], (#x in this).prop
  1008. if (p instanceof AST_PropAccess && p.expression === this) {
  1009. return true;
  1010. }
  1011. // same precedence as regular in operator
  1012. if (p instanceof AST_Binary) {
  1013. const parent_op = p.operator;
  1014. const pp = PRECEDENCE[parent_op];
  1015. const sp = PRECEDENCE["in"];
  1016. if (pp > sp
  1017. || (pp == sp
  1018. && (this === p.right || parent_op == "**"))) {
  1019. return true;
  1020. }
  1021. }
  1022. // rules are the same as binary in, but the class differs
  1023. if (p instanceof AST_PrivateIn && this === p.value) {
  1024. return true;
  1025. }
  1026. });
  1027. PARENS(AST_Yield, function(output) {
  1028. var p = output.parent();
  1029. // (yield 1) + (yield 2)
  1030. // a = yield 3
  1031. if (p instanceof AST_Binary && p.operator !== "=")
  1032. return true;
  1033. // (yield 1)()
  1034. // new (yield 1)()
  1035. if (p instanceof AST_Call && p.expression === this)
  1036. return true;
  1037. // (yield 1) ? yield 2 : yield 3
  1038. if (p instanceof AST_Conditional && p.condition === this)
  1039. return true;
  1040. // -(yield 4)
  1041. if (p instanceof AST_Unary)
  1042. return true;
  1043. // (yield x).foo
  1044. // (yield x)['foo']
  1045. if (p instanceof AST_PropAccess && p.expression === this)
  1046. return true;
  1047. });
  1048. PARENS(AST_Chain, function(output) {
  1049. var p = output.parent();
  1050. if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false;
  1051. return p.expression === this;
  1052. });
  1053. PARENS(AST_PropAccess, function(output) {
  1054. var p = output.parent();
  1055. if (p instanceof AST_New && p.expression === this) {
  1056. // i.e. new (foo.bar().baz)
  1057. //
  1058. // if there's one call into this subtree, then we need
  1059. // parens around it too, otherwise the call will be
  1060. // interpreted as passing the arguments to the upper New
  1061. // expression.
  1062. return walk(this, node => {
  1063. if (node instanceof AST_Scope) return true;
  1064. if (node instanceof AST_Call) {
  1065. return walk_abort; // makes walk() return true.
  1066. }
  1067. });
  1068. }
  1069. });
  1070. PARENS(AST_Call, function(output) {
  1071. var p = output.parent(), p1;
  1072. if (p instanceof AST_New && p.expression === this
  1073. || p instanceof AST_Export && p.is_default && this.expression instanceof AST_Function)
  1074. return true;
  1075. // workaround for Safari bug.
  1076. // https://bugs.webkit.org/show_bug.cgi?id=123506
  1077. return this.expression instanceof AST_Function
  1078. && p instanceof AST_PropAccess
  1079. && p.expression === this
  1080. && (p1 = output.parent(1)) instanceof AST_Assign
  1081. && p1.left === p;
  1082. });
  1083. PARENS(AST_New, function(output) {
  1084. var p = output.parent();
  1085. if (this.args.length === 0
  1086. && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
  1087. || p instanceof AST_Call && p.expression === this
  1088. || p instanceof AST_PrefixedTemplateString && p.prefix === this)) // (new foo)(bar)
  1089. return true;
  1090. });
  1091. PARENS(AST_Number, function(output) {
  1092. var p = output.parent();
  1093. if (p instanceof AST_PropAccess && p.expression === this) {
  1094. var value = this.getValue();
  1095. if (value < 0 || /^0/.test(make_num(value))) {
  1096. return true;
  1097. }
  1098. }
  1099. });
  1100. PARENS(AST_BigInt, function(output) {
  1101. var p = output.parent();
  1102. if (p instanceof AST_PropAccess && p.expression === this) {
  1103. var value = this.getValue();
  1104. if (value.startsWith("-")) {
  1105. return true;
  1106. }
  1107. }
  1108. });
  1109. PARENS([ AST_Assign, AST_Conditional ], function(output) {
  1110. var p = output.parent();
  1111. // !(a = false) → true
  1112. if (p instanceof AST_Unary)
  1113. return true;
  1114. // 1 + (a = 2) + 3 → 6, side effect setting a = 2
  1115. if (p instanceof AST_Binary && !(p instanceof AST_Assign))
  1116. return true;
  1117. // (a = func)() —or— new (a = Object)()
  1118. if (p instanceof AST_Call && p.expression === this)
  1119. return true;
  1120. // (a = foo) ? bar : baz
  1121. if (p instanceof AST_Conditional && p.condition === this)
  1122. return true;
  1123. // (a = foo)["prop"] —or— (a = foo).prop
  1124. if (p instanceof AST_PropAccess && p.expression === this)
  1125. return true;
  1126. // ({a, b} = {a: 1, b: 2}), a destructuring assignment
  1127. if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false)
  1128. return true;
  1129. });
  1130. /* -----[ PRINTERS ]----- */
  1131. DEFPRINT(AST_Directive, function(self, output) {
  1132. output.print_string(self.value, self.quote);
  1133. output.semicolon();
  1134. });
  1135. DEFPRINT(AST_Expansion, function (self, output) {
  1136. output.print("...");
  1137. self.expression.print(output);
  1138. });
  1139. DEFPRINT(AST_Destructuring, function (self, output) {
  1140. output.print(self.is_array ? "[" : "{");
  1141. var len = self.names.length;
  1142. self.names.forEach(function (name, i) {
  1143. if (i > 0) output.comma();
  1144. name.print(output);
  1145. // If the final element is a hole, we need to make sure it
  1146. // doesn't look like a trailing comma, by inserting an actual
  1147. // trailing comma.
  1148. if (i == len - 1 && name instanceof AST_Hole) output.comma();
  1149. });
  1150. output.print(self.is_array ? "]" : "}");
  1151. });
  1152. DEFPRINT(AST_Debugger, function(self, output) {
  1153. output.print("debugger");
  1154. output.semicolon();
  1155. });
  1156. /* -----[ statements ]----- */
  1157. function display_body(body, is_toplevel, output, allow_directives) {
  1158. var last = body.length - 1;
  1159. output.in_directive = allow_directives;
  1160. body.forEach(function(stmt, i) {
  1161. if (output.in_directive === true && !(stmt instanceof AST_Directive ||
  1162. stmt instanceof AST_EmptyStatement ||
  1163. (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
  1164. )) {
  1165. output.in_directive = false;
  1166. }
  1167. if (!(stmt instanceof AST_EmptyStatement)) {
  1168. output.indent();
  1169. stmt.print(output);
  1170. if (!(i == last && is_toplevel)) {
  1171. output.newline();
  1172. if (is_toplevel) output.newline();
  1173. }
  1174. }
  1175. if (output.in_directive === true &&
  1176. stmt instanceof AST_SimpleStatement &&
  1177. stmt.body instanceof AST_String
  1178. ) {
  1179. output.in_directive = false;
  1180. }
  1181. });
  1182. output.in_directive = false;
  1183. }
  1184. AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
  1185. print_maybe_braced_body(this.body, output);
  1186. });
  1187. DEFPRINT(AST_Statement, function(self, output) {
  1188. self.body.print(output);
  1189. output.semicolon();
  1190. });
  1191. DEFPRINT(AST_Toplevel, function(self, output) {
  1192. display_body(self.body, true, output, true);
  1193. output.print("");
  1194. });
  1195. DEFPRINT(AST_LabeledStatement, function(self, output) {
  1196. self.label.print(output);
  1197. output.colon();
  1198. self.body.print(output);
  1199. });
  1200. DEFPRINT(AST_SimpleStatement, function(self, output) {
  1201. self.body.print(output);
  1202. output.semicolon();
  1203. });
  1204. function print_braced_empty(self, output) {
  1205. output.print("{");
  1206. output.with_indent(output.next_indent(), function() {
  1207. output.append_comments(self, true);
  1208. });
  1209. output.add_mapping(self.end);
  1210. output.print("}");
  1211. }
  1212. function print_braced(self, output, allow_directives) {
  1213. if (self.body.length > 0) {
  1214. output.with_block(function() {
  1215. display_body(self.body, false, output, allow_directives);
  1216. output.add_mapping(self.end);
  1217. });
  1218. } else print_braced_empty(self, output);
  1219. }
  1220. DEFPRINT(AST_BlockStatement, function(self, output) {
  1221. print_braced(self, output);
  1222. });
  1223. DEFPRINT(AST_EmptyStatement, function(self, output) {
  1224. output.semicolon();
  1225. });
  1226. DEFPRINT(AST_Do, function(self, output) {
  1227. output.print("do");
  1228. output.space();
  1229. make_block(self.body, output);
  1230. output.space();
  1231. output.print("while");
  1232. output.space();
  1233. output.with_parens(function() {
  1234. self.condition.print(output);
  1235. });
  1236. output.semicolon();
  1237. });
  1238. DEFPRINT(AST_While, function(self, output) {
  1239. output.print("while");
  1240. output.space();
  1241. output.with_parens(function() {
  1242. self.condition.print(output);
  1243. });
  1244. output.space();
  1245. self._do_print_body(output);
  1246. });
  1247. DEFPRINT(AST_For, function(self, output) {
  1248. output.print("for");
  1249. output.space();
  1250. output.with_parens(function() {
  1251. if (self.init) {
  1252. if (self.init instanceof AST_Definitions) {
  1253. self.init.print(output);
  1254. } else {
  1255. parenthesize_for_noin(self.init, output, true);
  1256. }
  1257. output.print(";");
  1258. output.space();
  1259. } else {
  1260. output.print(";");
  1261. }
  1262. if (self.condition) {
  1263. self.condition.print(output);
  1264. output.print(";");
  1265. output.space();
  1266. } else {
  1267. output.print(";");
  1268. }
  1269. if (self.step) {
  1270. self.step.print(output);
  1271. }
  1272. });
  1273. output.space();
  1274. self._do_print_body(output);
  1275. });
  1276. DEFPRINT(AST_ForIn, function(self, output) {
  1277. output.print("for");
  1278. if (self.await) {
  1279. output.space();
  1280. output.print("await");
  1281. }
  1282. output.space();
  1283. output.with_parens(function() {
  1284. self.init.print(output);
  1285. output.space();
  1286. output.print(self instanceof AST_ForOf ? "of" : "in");
  1287. output.space();
  1288. self.object.print(output);
  1289. });
  1290. output.space();
  1291. self._do_print_body(output);
  1292. });
  1293. DEFPRINT(AST_With, function(self, output) {
  1294. output.print("with");
  1295. output.space();
  1296. output.with_parens(function() {
  1297. self.expression.print(output);
  1298. });
  1299. output.space();
  1300. self._do_print_body(output);
  1301. });
  1302. /* -----[ functions ]----- */
  1303. AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
  1304. var self = this;
  1305. if (!nokeyword) {
  1306. if (self.async) {
  1307. output.print("async");
  1308. output.space();
  1309. }
  1310. output.print("function");
  1311. if (self.is_generator) {
  1312. output.star();
  1313. }
  1314. if (self.name) {
  1315. output.space();
  1316. }
  1317. }
  1318. if (self.name instanceof AST_Symbol) {
  1319. self.name.print(output);
  1320. } else if (nokeyword && self.name instanceof AST_Node) {
  1321. output.with_square(function() {
  1322. self.name.print(output); // Computed method name
  1323. });
  1324. }
  1325. output.with_parens(function() {
  1326. self.argnames.forEach(function(arg, i) {
  1327. if (i) output.comma();
  1328. arg.print(output);
  1329. });
  1330. });
  1331. output.space();
  1332. print_braced(self, output, true);
  1333. });
  1334. DEFPRINT(AST_Lambda, function(self, output) {
  1335. self._do_print(output);
  1336. output.gc_scope(self);
  1337. });
  1338. DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
  1339. var tag = self.prefix;
  1340. var parenthesize_tag = tag instanceof AST_Lambda
  1341. || tag instanceof AST_Binary
  1342. || tag instanceof AST_Conditional
  1343. || tag instanceof AST_Sequence
  1344. || tag instanceof AST_Unary
  1345. || tag instanceof AST_Dot && tag.expression instanceof AST_Object;
  1346. if (parenthesize_tag) output.print("(");
  1347. self.prefix.print(output);
  1348. if (parenthesize_tag) output.print(")");
  1349. self.template_string.print(output);
  1350. });
  1351. DEFPRINT(AST_TemplateString, function(self, output) {
  1352. var is_tagged = output.parent() instanceof AST_PrefixedTemplateString;
  1353. output.print("`");
  1354. for (var i = 0; i < self.segments.length; i++) {
  1355. if (!(self.segments[i] instanceof AST_TemplateSegment)) {
  1356. output.print("${");
  1357. self.segments[i].print(output);
  1358. output.print("}");
  1359. } else if (is_tagged) {
  1360. output.print(self.segments[i].raw);
  1361. } else {
  1362. output.print_template_string_chars(self.segments[i].value);
  1363. }
  1364. }
  1365. output.print("`");
  1366. });
  1367. DEFPRINT(AST_TemplateSegment, function(self, output) {
  1368. output.print_template_string_chars(self.value);
  1369. });
  1370. AST_Arrow.DEFMETHOD("_do_print", function(output) {
  1371. var self = this;
  1372. var parent = output.parent();
  1373. var needs_parens = (parent instanceof AST_Binary &&
  1374. !(parent instanceof AST_Assign) &&
  1375. !(parent instanceof AST_DefaultAssign)) ||
  1376. parent instanceof AST_Unary ||
  1377. (parent instanceof AST_Call && self === parent.expression);
  1378. if (needs_parens) { output.print("("); }
  1379. if (self.async) {
  1380. output.print("async");
  1381. output.space();
  1382. }
  1383. if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
  1384. self.argnames[0].print(output);
  1385. } else {
  1386. output.with_parens(function() {
  1387. self.argnames.forEach(function(arg, i) {
  1388. if (i) output.comma();
  1389. arg.print(output);
  1390. });
  1391. });
  1392. }
  1393. output.space();
  1394. output.print("=>");
  1395. output.space();
  1396. const first_statement = self.body[0];
  1397. if (
  1398. self.body.length === 1
  1399. && first_statement instanceof AST_Return
  1400. ) {
  1401. const returned = first_statement.value;
  1402. if (!returned) {
  1403. output.print("{}");
  1404. } else if (left_is_object(returned)) {
  1405. output.print("(");
  1406. returned.print(output);
  1407. output.print(")");
  1408. } else {
  1409. returned.print(output);
  1410. }
  1411. } else {
  1412. print_braced(self, output);
  1413. }
  1414. if (needs_parens) { output.print(")"); }
  1415. output.gc_scope(self);
  1416. });
  1417. /* -----[ exits ]----- */
  1418. AST_Exit.DEFMETHOD("_do_print", function(output, kind) {
  1419. output.print(kind);
  1420. if (this.value) {
  1421. output.space();
  1422. const comments = this.value.start.comments_before;
  1423. if (comments && comments.length && !output.printed_comments.has(comments)) {
  1424. output.print("(");
  1425. this.value.print(output);
  1426. output.print(")");
  1427. } else {
  1428. this.value.print(output);
  1429. }
  1430. }
  1431. output.semicolon();
  1432. });
  1433. DEFPRINT(AST_Return, function(self, output) {
  1434. self._do_print(output, "return");
  1435. });
  1436. DEFPRINT(AST_Throw, function(self, output) {
  1437. self._do_print(output, "throw");
  1438. });
  1439. /* -----[ yield ]----- */
  1440. DEFPRINT(AST_Yield, function(self, output) {
  1441. var star = self.is_star ? "*" : "";
  1442. output.print("yield" + star);
  1443. if (self.expression) {
  1444. output.space();
  1445. self.expression.print(output);
  1446. }
  1447. });
  1448. DEFPRINT(AST_Await, function(self, output) {
  1449. output.print("await");
  1450. output.space();
  1451. var e = self.expression;
  1452. var parens = !(
  1453. e instanceof AST_Call
  1454. || e instanceof AST_SymbolRef
  1455. || e instanceof AST_PropAccess
  1456. || e instanceof AST_Unary
  1457. || e instanceof AST_Constant
  1458. || e instanceof AST_Await
  1459. || e instanceof AST_Object
  1460. );
  1461. if (parens) output.print("(");
  1462. self.expression.print(output);
  1463. if (parens) output.print(")");
  1464. });
  1465. /* -----[ loop control ]----- */
  1466. AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) {
  1467. output.print(kind);
  1468. if (this.label) {
  1469. output.space();
  1470. this.label.print(output);
  1471. }
  1472. output.semicolon();
  1473. });
  1474. DEFPRINT(AST_Break, function(self, output) {
  1475. self._do_print(output, "break");
  1476. });
  1477. DEFPRINT(AST_Continue, function(self, output) {
  1478. self._do_print(output, "continue");
  1479. });
  1480. /* -----[ if ]----- */
  1481. function make_then(self, output) {
  1482. var b = self.body;
  1483. if (output.option("braces")
  1484. || output.option("ie8") && b instanceof AST_Do)
  1485. return make_block(b, output);
  1486. // The squeezer replaces "block"-s that contain only a single
  1487. // statement with the statement itself; technically, the AST
  1488. // is correct, but this can create problems when we output an
  1489. // IF having an ELSE clause where the THEN clause ends in an
  1490. // IF *without* an ELSE block (then the outer ELSE would refer
  1491. // to the inner IF). This function checks for this case and
  1492. // adds the block braces if needed.
  1493. if (!b) return output.force_semicolon();
  1494. while (true) {
  1495. if (b instanceof AST_If) {
  1496. if (!b.alternative) {
  1497. make_block(self.body, output);
  1498. return;
  1499. }
  1500. b = b.alternative;
  1501. } else if (b instanceof AST_StatementWithBody) {
  1502. b = b.body;
  1503. } else break;
  1504. }
  1505. print_maybe_braced_body(self.body, output);
  1506. }
  1507. DEFPRINT(AST_If, function(self, output) {
  1508. output.print("if");
  1509. output.space();
  1510. output.with_parens(function() {
  1511. self.condition.print(output);
  1512. });
  1513. output.space();
  1514. if (self.alternative) {
  1515. make_then(self, output);
  1516. output.space();
  1517. output.print("else");
  1518. output.space();
  1519. if (self.alternative instanceof AST_If)
  1520. self.alternative.print(output);
  1521. else
  1522. print_maybe_braced_body(self.alternative, output);
  1523. } else {
  1524. self._do_print_body(output);
  1525. }
  1526. });
  1527. /* -----[ switch ]----- */
  1528. DEFPRINT(AST_Switch, function(self, output) {
  1529. output.print("switch");
  1530. output.space();
  1531. output.with_parens(function() {
  1532. self.expression.print(output);
  1533. });
  1534. output.space();
  1535. var last = self.body.length - 1;
  1536. if (last < 0) print_braced_empty(self, output);
  1537. else output.with_block(function() {
  1538. self.body.forEach(function(branch, i) {
  1539. output.indent(true);
  1540. branch.print(output);
  1541. if (i < last && branch.body.length > 0)
  1542. output.newline();
  1543. });
  1544. });
  1545. });
  1546. AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
  1547. output.newline();
  1548. this.body.forEach(function(stmt) {
  1549. output.indent();
  1550. stmt.print(output);
  1551. output.newline();
  1552. });
  1553. });
  1554. DEFPRINT(AST_Default, function(self, output) {
  1555. output.print("default:");
  1556. self._do_print_body(output);
  1557. });
  1558. DEFPRINT(AST_Case, function(self, output) {
  1559. output.print("case");
  1560. output.space();
  1561. self.expression.print(output);
  1562. output.print(":");
  1563. self._do_print_body(output);
  1564. });
  1565. /* -----[ exceptions ]----- */
  1566. DEFPRINT(AST_Try, function(self, output) {
  1567. output.print("try");
  1568. output.space();
  1569. self.body.print(output);
  1570. if (self.bcatch) {
  1571. output.space();
  1572. self.bcatch.print(output);
  1573. }
  1574. if (self.bfinally) {
  1575. output.space();
  1576. self.bfinally.print(output);
  1577. }
  1578. });
  1579. DEFPRINT(AST_TryBlock, function(self, output) {
  1580. print_braced(self, output);
  1581. });
  1582. DEFPRINT(AST_Catch, function(self, output) {
  1583. output.print("catch");
  1584. if (self.argname) {
  1585. output.space();
  1586. output.with_parens(function() {
  1587. self.argname.print(output);
  1588. });
  1589. }
  1590. output.space();
  1591. print_braced(self, output);
  1592. });
  1593. DEFPRINT(AST_Finally, function(self, output) {
  1594. output.print("finally");
  1595. output.space();
  1596. print_braced(self, output);
  1597. });
  1598. /* -----[ var/const ]----- */
  1599. AST_Definitions.DEFMETHOD("_do_print", function(output, kind) {
  1600. output.print(kind);
  1601. output.space();
  1602. this.definitions.forEach(function(def, i) {
  1603. if (i) output.comma();
  1604. def.print(output);
  1605. });
  1606. var p = output.parent();
  1607. var in_for = p instanceof AST_For || p instanceof AST_ForIn;
  1608. var output_semicolon = !in_for || p && p.init !== this;
  1609. if (output_semicolon)
  1610. output.semicolon();
  1611. });
  1612. DEFPRINT(AST_Let, function(self, output) {
  1613. self._do_print(output, "let");
  1614. });
  1615. DEFPRINT(AST_Var, function(self, output) {
  1616. self._do_print(output, "var");
  1617. });
  1618. DEFPRINT(AST_Const, function(self, output) {
  1619. self._do_print(output, "const");
  1620. });
  1621. DEFPRINT(AST_Import, function(self, output) {
  1622. output.print("import");
  1623. output.space();
  1624. if (self.imported_name) {
  1625. self.imported_name.print(output);
  1626. }
  1627. if (self.imported_name && self.imported_names) {
  1628. output.print(",");
  1629. output.space();
  1630. }
  1631. if (self.imported_names) {
  1632. if (self.imported_names.length === 1 &&
  1633. self.imported_names[0].foreign_name.name === "*" &&
  1634. !self.imported_names[0].foreign_name.quote) {
  1635. self.imported_names[0].print(output);
  1636. } else {
  1637. output.print("{");
  1638. self.imported_names.forEach(function (name_import, i) {
  1639. output.space();
  1640. name_import.print(output);
  1641. if (i < self.imported_names.length - 1) {
  1642. output.print(",");
  1643. }
  1644. });
  1645. output.space();
  1646. output.print("}");
  1647. }
  1648. }
  1649. if (self.imported_name || self.imported_names) {
  1650. output.space();
  1651. output.print("from");
  1652. output.space();
  1653. }
  1654. self.module_name.print(output);
  1655. if (self.assert_clause) {
  1656. output.print("assert");
  1657. self.assert_clause.print(output);
  1658. }
  1659. output.semicolon();
  1660. });
  1661. DEFPRINT(AST_ImportMeta, function(self, output) {
  1662. output.print("import.meta");
  1663. });
  1664. DEFPRINT(AST_NameMapping, function(self, output) {
  1665. var is_import = output.parent() instanceof AST_Import;
  1666. var definition = self.name.definition();
  1667. var foreign_name = self.foreign_name;
  1668. var names_are_different =
  1669. (definition && definition.mangled_name || self.name.name) !==
  1670. foreign_name.name;
  1671. if (!names_are_different &&
  1672. foreign_name.name === "*" &&
  1673. foreign_name.quote != self.name.quote) {
  1674. // export * as "*"
  1675. names_are_different = true;
  1676. }
  1677. var foreign_name_is_name = foreign_name.quote == null;
  1678. if (names_are_different) {
  1679. if (is_import) {
  1680. if (foreign_name_is_name) {
  1681. output.print(foreign_name.name);
  1682. } else {
  1683. output.print_string(foreign_name.name, foreign_name.quote);
  1684. }
  1685. } else {
  1686. if (self.name.quote == null) {
  1687. self.name.print(output);
  1688. } else {
  1689. output.print_string(self.name.name, self.name.quote);
  1690. }
  1691. }
  1692. output.space();
  1693. output.print("as");
  1694. output.space();
  1695. if (is_import) {
  1696. self.name.print(output);
  1697. } else {
  1698. if (foreign_name_is_name) {
  1699. output.print(foreign_name.name);
  1700. } else {
  1701. output.print_string(foreign_name.name, foreign_name.quote);
  1702. }
  1703. }
  1704. } else {
  1705. if (self.name.quote == null) {
  1706. self.name.print(output);
  1707. } else {
  1708. output.print_string(self.name.name, self.name.quote);
  1709. }
  1710. }
  1711. });
  1712. DEFPRINT(AST_Export, function(self, output) {
  1713. output.print("export");
  1714. output.space();
  1715. if (self.is_default) {
  1716. output.print("default");
  1717. output.space();
  1718. }
  1719. if (self.exported_names) {
  1720. if (self.exported_names.length === 1 &&
  1721. self.exported_names[0].name.name === "*" &&
  1722. !self.exported_names[0].name.quote) {
  1723. self.exported_names[0].print(output);
  1724. } else {
  1725. output.print("{");
  1726. self.exported_names.forEach(function(name_export, i) {
  1727. output.space();
  1728. name_export.print(output);
  1729. if (i < self.exported_names.length - 1) {
  1730. output.print(",");
  1731. }
  1732. });
  1733. output.space();
  1734. output.print("}");
  1735. }
  1736. } else if (self.exported_value) {
  1737. self.exported_value.print(output);
  1738. } else if (self.exported_definition) {
  1739. self.exported_definition.print(output);
  1740. if (self.exported_definition instanceof AST_Definitions) return;
  1741. }
  1742. if (self.module_name) {
  1743. output.space();
  1744. output.print("from");
  1745. output.space();
  1746. self.module_name.print(output);
  1747. }
  1748. if (self.assert_clause) {
  1749. output.print("assert");
  1750. self.assert_clause.print(output);
  1751. }
  1752. if (self.exported_value
  1753. && !(self.exported_value instanceof AST_Defun ||
  1754. self.exported_value instanceof AST_Function ||
  1755. self.exported_value instanceof AST_Class)
  1756. || self.module_name
  1757. || self.exported_names
  1758. ) {
  1759. output.semicolon();
  1760. }
  1761. });
  1762. function parenthesize_for_noin(node, output, noin) {
  1763. var parens = false;
  1764. // need to take some precautions here:
  1765. // https://github.com/mishoo/UglifyJS2/issues/60
  1766. if (noin) {
  1767. parens = walk(node, node => {
  1768. // Don't go into scopes -- except arrow functions:
  1769. // https://github.com/terser/terser/issues/1019#issuecomment-877642607
  1770. if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
  1771. return true;
  1772. }
  1773. if (
  1774. node instanceof AST_Binary && node.operator == "in"
  1775. || node instanceof AST_PrivateIn
  1776. ) {
  1777. return walk_abort; // makes walk() return true
  1778. }
  1779. });
  1780. }
  1781. node.print(output, parens);
  1782. }
  1783. DEFPRINT(AST_VarDef, function(self, output) {
  1784. self.name.print(output);
  1785. if (self.value) {
  1786. output.space();
  1787. output.print("=");
  1788. output.space();
  1789. var p = output.parent(1);
  1790. var noin = p instanceof AST_For || p instanceof AST_ForIn;
  1791. parenthesize_for_noin(self.value, output, noin);
  1792. }
  1793. });
  1794. /* -----[ other expressions ]----- */
  1795. DEFPRINT(AST_Call, function(self, output) {
  1796. self.expression.print(output);
  1797. if (self instanceof AST_New && self.args.length === 0)
  1798. return;
  1799. if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
  1800. output.add_mapping(self.start);
  1801. }
  1802. if (self.optional) output.print("?.");
  1803. output.with_parens(function() {
  1804. self.args.forEach(function(expr, i) {
  1805. if (i) output.comma();
  1806. expr.print(output);
  1807. });
  1808. });
  1809. });
  1810. DEFPRINT(AST_New, function(self, output) {
  1811. output.print("new");
  1812. output.space();
  1813. AST_Call.prototype._codegen(self, output);
  1814. });
  1815. AST_Sequence.DEFMETHOD("_do_print", function(output) {
  1816. this.expressions.forEach(function(node, index) {
  1817. if (index > 0) {
  1818. output.comma();
  1819. if (output.should_break()) {
  1820. output.newline();
  1821. output.indent();
  1822. }
  1823. }
  1824. node.print(output);
  1825. });
  1826. });
  1827. DEFPRINT(AST_Sequence, function(self, output) {
  1828. self._do_print(output);
  1829. // var p = output.parent();
  1830. // if (p instanceof AST_Statement) {
  1831. // output.with_indent(output.next_indent(), function(){
  1832. // self._do_print(output);
  1833. // });
  1834. // } else {
  1835. // self._do_print(output);
  1836. // }
  1837. });
  1838. DEFPRINT(AST_Dot, function(self, output) {
  1839. var expr = self.expression;
  1840. expr.print(output);
  1841. var prop = self.property;
  1842. var print_computed = ALL_RESERVED_WORDS.has(prop)
  1843. ? output.option("ie8")
  1844. : !is_identifier_string(
  1845. prop,
  1846. output.option("ecma") >= 2015 && !output.option("safari10")
  1847. );
  1848. if (self.optional) output.print("?.");
  1849. if (print_computed) {
  1850. output.print("[");
  1851. output.add_mapping(self.end);
  1852. output.print_string(prop);
  1853. output.print("]");
  1854. } else {
  1855. if (expr instanceof AST_Number && expr.getValue() >= 0) {
  1856. if (!/[xa-f.)]/i.test(output.last())) {
  1857. output.print(".");
  1858. }
  1859. }
  1860. if (!self.optional) output.print(".");
  1861. // the name after dot would be mapped about here.
  1862. output.add_mapping(self.end);
  1863. output.print_name(prop);
  1864. }
  1865. });
  1866. DEFPRINT(AST_DotHash, function(self, output) {
  1867. var expr = self.expression;
  1868. expr.print(output);
  1869. var prop = self.property;
  1870. if (self.optional) output.print("?");
  1871. output.print(".#");
  1872. output.add_mapping(self.end);
  1873. output.print_name(prop);
  1874. });
  1875. DEFPRINT(AST_Sub, function(self, output) {
  1876. self.expression.print(output);
  1877. if (self.optional) output.print("?.");
  1878. output.print("[");
  1879. self.property.print(output);
  1880. output.print("]");
  1881. });
  1882. DEFPRINT(AST_Chain, function(self, output) {
  1883. self.expression.print(output);
  1884. });
  1885. DEFPRINT(AST_UnaryPrefix, function(self, output) {
  1886. var op = self.operator;
  1887. if (op === "--" && output.last().endsWith("!")) {
  1888. // avoid printing "<!--"
  1889. output.print(" ");
  1890. }
  1891. output.print(op);
  1892. if (/^[a-z]/i.test(op)
  1893. || (/[+-]$/.test(op)
  1894. && self.expression instanceof AST_UnaryPrefix
  1895. && /^[+-]/.test(self.expression.operator))) {
  1896. output.space();
  1897. }
  1898. self.expression.print(output);
  1899. });
  1900. DEFPRINT(AST_UnaryPostfix, function(self, output) {
  1901. self.expression.print(output);
  1902. output.print(self.operator);
  1903. });
  1904. DEFPRINT(AST_Binary, function(self, output) {
  1905. var op = self.operator;
  1906. self.left.print(output);
  1907. if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
  1908. && output.last().endsWith("--")) {
  1909. // space is mandatory to avoid outputting -->
  1910. output.print(" ");
  1911. } else {
  1912. // the space is optional depending on "beautify"
  1913. output.space();
  1914. }
  1915. output.print(op);
  1916. output.space();
  1917. self.right.print(output);
  1918. });
  1919. DEFPRINT(AST_Conditional, function(self, output) {
  1920. self.condition.print(output);
  1921. output.space();
  1922. output.print("?");
  1923. output.space();
  1924. self.consequent.print(output);
  1925. output.space();
  1926. output.colon();
  1927. self.alternative.print(output);
  1928. });
  1929. /* -----[ literals ]----- */
  1930. DEFPRINT(AST_Array, function(self, output) {
  1931. output.with_square(function() {
  1932. var a = self.elements, len = a.length;
  1933. if (len > 0) output.space();
  1934. a.forEach(function(exp, i) {
  1935. if (i) output.comma();
  1936. exp.print(output);
  1937. // If the final element is a hole, we need to make sure it
  1938. // doesn't look like a trailing comma, by inserting an actual
  1939. // trailing comma.
  1940. if (i === len - 1 && exp instanceof AST_Hole)
  1941. output.comma();
  1942. });
  1943. if (len > 0) output.space();
  1944. });
  1945. });
  1946. DEFPRINT(AST_Object, function(self, output) {
  1947. if (self.properties.length > 0) output.with_block(function() {
  1948. self.properties.forEach(function(prop, i) {
  1949. if (i) {
  1950. output.print(",");
  1951. output.newline();
  1952. }
  1953. output.indent();
  1954. prop.print(output);
  1955. });
  1956. output.newline();
  1957. });
  1958. else print_braced_empty(self, output);
  1959. });
  1960. DEFPRINT(AST_Class, function(self, output) {
  1961. output.print("class");
  1962. output.space();
  1963. if (self.name) {
  1964. self.name.print(output);
  1965. output.space();
  1966. }
  1967. if (self.extends) {
  1968. var parens = (
  1969. !(self.extends instanceof AST_SymbolRef)
  1970. && !(self.extends instanceof AST_PropAccess)
  1971. && !(self.extends instanceof AST_ClassExpression)
  1972. && !(self.extends instanceof AST_Function)
  1973. );
  1974. output.print("extends");
  1975. if (parens) {
  1976. output.print("(");
  1977. } else {
  1978. output.space();
  1979. }
  1980. self.extends.print(output);
  1981. if (parens) {
  1982. output.print(")");
  1983. } else {
  1984. output.space();
  1985. }
  1986. }
  1987. if (self.properties.length > 0) output.with_block(function() {
  1988. self.properties.forEach(function(prop, i) {
  1989. if (i) {
  1990. output.newline();
  1991. }
  1992. output.indent();
  1993. prop.print(output);
  1994. });
  1995. output.newline();
  1996. });
  1997. else output.print("{}");
  1998. });
  1999. DEFPRINT(AST_NewTarget, function(self, output) {
  2000. output.print("new.target");
  2001. });
  2002. /** Prints a prop name. Returns whether it can be used as a shorthand. */
  2003. function print_property_name(key, quote, output) {
  2004. if (output.option("quote_keys")) {
  2005. output.print_string(key);
  2006. return false;
  2007. }
  2008. if ("" + +key == key && key >= 0) {
  2009. if (output.option("keep_numbers")) {
  2010. output.print(key);
  2011. return false;
  2012. }
  2013. output.print(make_num(key));
  2014. return false;
  2015. }
  2016. var print_string = ALL_RESERVED_WORDS.has(key)
  2017. ? output.option("ie8")
  2018. : (
  2019. output.option("ecma") < 2015 || output.option("safari10")
  2020. ? !is_basic_identifier_string(key)
  2021. : !is_identifier_string(key, true)
  2022. );
  2023. if (print_string || (quote && output.option("keep_quoted_props"))) {
  2024. output.print_string(key, quote);
  2025. return false;
  2026. }
  2027. output.print_name(key);
  2028. return true;
  2029. }
  2030. DEFPRINT(AST_ObjectKeyVal, function(self, output) {
  2031. function get_name(self) {
  2032. var def = self.definition();
  2033. return def ? def.mangled_name || def.name : self.name;
  2034. }
  2035. const try_shorthand = output.option("shorthand") && !(self.key instanceof AST_Node);
  2036. if (
  2037. try_shorthand
  2038. && self.value instanceof AST_Symbol
  2039. && get_name(self.value) === self.key
  2040. && !ALL_RESERVED_WORDS.has(self.key)
  2041. ) {
  2042. const was_shorthand = print_property_name(self.key, self.quote, output);
  2043. if (!was_shorthand) {
  2044. output.colon();
  2045. self.value.print(output);
  2046. }
  2047. } else if (
  2048. try_shorthand
  2049. && self.value instanceof AST_DefaultAssign
  2050. && self.value.left instanceof AST_Symbol
  2051. && get_name(self.value.left) === self.key
  2052. ) {
  2053. const was_shorthand = print_property_name(self.key, self.quote, output);
  2054. if (!was_shorthand) {
  2055. output.colon();
  2056. self.value.left.print(output);
  2057. }
  2058. output.space();
  2059. output.print("=");
  2060. output.space();
  2061. self.value.right.print(output);
  2062. } else {
  2063. if (!(self.key instanceof AST_Node)) {
  2064. print_property_name(self.key, self.quote, output);
  2065. } else {
  2066. output.with_square(function() {
  2067. self.key.print(output);
  2068. });
  2069. }
  2070. output.colon();
  2071. self.value.print(output);
  2072. }
  2073. });
  2074. DEFPRINT(AST_ClassPrivateProperty, (self, output) => {
  2075. if (self.static) {
  2076. output.print("static");
  2077. output.space();
  2078. }
  2079. output.print("#");
  2080. print_property_name(self.key.name, self.quote, output);
  2081. if (self.value) {
  2082. output.print("=");
  2083. self.value.print(output);
  2084. }
  2085. output.semicolon();
  2086. });
  2087. DEFPRINT(AST_ClassProperty, (self, output) => {
  2088. if (self.static) {
  2089. output.print("static");
  2090. output.space();
  2091. }
  2092. if (self.key instanceof AST_SymbolClassProperty) {
  2093. print_property_name(self.key.name, self.quote, output);
  2094. } else {
  2095. output.print("[");
  2096. self.key.print(output);
  2097. output.print("]");
  2098. }
  2099. if (self.value) {
  2100. output.print("=");
  2101. self.value.print(output);
  2102. }
  2103. output.semicolon();
  2104. });
  2105. AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, is_private, output) {
  2106. var self = this;
  2107. if (self.static) {
  2108. output.print("static");
  2109. output.space();
  2110. }
  2111. if (type) {
  2112. output.print(type);
  2113. output.space();
  2114. }
  2115. if (self.key instanceof AST_SymbolMethod) {
  2116. if (is_private) output.print("#");
  2117. print_property_name(self.key.name, self.quote, output);
  2118. self.key.add_source_map(output);
  2119. } else {
  2120. output.with_square(function() {
  2121. self.key.print(output);
  2122. });
  2123. }
  2124. self.value._do_print(output, true);
  2125. });
  2126. DEFPRINT(AST_ObjectSetter, function(self, output) {
  2127. self._print_getter_setter("set", false, output);
  2128. });
  2129. DEFPRINT(AST_ObjectGetter, function(self, output) {
  2130. self._print_getter_setter("get", false, output);
  2131. });
  2132. DEFPRINT(AST_PrivateSetter, function(self, output) {
  2133. self._print_getter_setter("set", true, output);
  2134. });
  2135. DEFPRINT(AST_PrivateGetter, function(self, output) {
  2136. self._print_getter_setter("get", true, output);
  2137. });
  2138. DEFPRINT(AST_PrivateMethod, function(self, output) {
  2139. var type;
  2140. if (self.is_generator && self.async) {
  2141. type = "async*";
  2142. } else if (self.is_generator) {
  2143. type = "*";
  2144. } else if (self.async) {
  2145. type = "async";
  2146. }
  2147. self._print_getter_setter(type, true, output);
  2148. });
  2149. DEFPRINT(AST_PrivateIn, function(self, output) {
  2150. self.key.print(output);
  2151. output.space();
  2152. output.print("in");
  2153. output.space();
  2154. self.value.print(output);
  2155. });
  2156. DEFPRINT(AST_SymbolPrivateProperty, function(self, output) {
  2157. output.print("#" + self.name);
  2158. });
  2159. DEFPRINT(AST_ConciseMethod, function(self, output) {
  2160. var type;
  2161. if (self.is_generator && self.async) {
  2162. type = "async*";
  2163. } else if (self.is_generator) {
  2164. type = "*";
  2165. } else if (self.async) {
  2166. type = "async";
  2167. }
  2168. self._print_getter_setter(type, false, output);
  2169. });
  2170. DEFPRINT(AST_ClassStaticBlock, function (self, output) {
  2171. output.print("static");
  2172. output.space();
  2173. print_braced(self, output);
  2174. });
  2175. AST_Symbol.DEFMETHOD("_do_print", function(output) {
  2176. var def = this.definition();
  2177. output.print_name(def ? def.mangled_name || def.name : this.name);
  2178. });
  2179. DEFPRINT(AST_Symbol, function (self, output) {
  2180. self._do_print(output);
  2181. });
  2182. DEFPRINT(AST_Hole, noop);
  2183. DEFPRINT(AST_This, function(self, output) {
  2184. output.print("this");
  2185. });
  2186. DEFPRINT(AST_Super, function(self, output) {
  2187. output.print("super");
  2188. });
  2189. DEFPRINT(AST_Constant, function(self, output) {
  2190. output.print(self.getValue());
  2191. });
  2192. DEFPRINT(AST_String, function(self, output) {
  2193. output.print_string(self.getValue(), self.quote, output.in_directive);
  2194. });
  2195. DEFPRINT(AST_Number, function(self, output) {
  2196. if ((output.option("keep_numbers") || output.use_asm) && self.raw) {
  2197. output.print(self.raw);
  2198. } else {
  2199. output.print(make_num(self.getValue()));
  2200. }
  2201. });
  2202. DEFPRINT(AST_BigInt, function(self, output) {
  2203. output.print(self.getValue() + "n");
  2204. });
  2205. const r_slash_script = /(<\s*\/\s*script)/i;
  2206. const r_starts_with_script = /^\s*script/i;
  2207. const slash_script_replace = (_, $1) => $1.replace("/", "\\/");
  2208. DEFPRINT(AST_RegExp, function(self, output) {
  2209. let { source, flags } = self.getValue();
  2210. source = regexp_source_fix(source);
  2211. flags = flags ? sort_regexp_flags(flags) : "";
  2212. // Avoid outputting end of script tag
  2213. source = source.replace(r_slash_script, slash_script_replace);
  2214. if (r_starts_with_script.test(source) && output.last().endsWith("<")) {
  2215. output.print(" ");
  2216. }
  2217. output.print(output.to_utf8(`/${source}/${flags}`, false, true));
  2218. const parent = output.parent();
  2219. if (
  2220. parent instanceof AST_Binary
  2221. && /^\w/.test(parent.operator)
  2222. && parent.left === self
  2223. ) {
  2224. output.print(" ");
  2225. }
  2226. });
  2227. /** if, for, while, may or may not have braces surrounding its body */
  2228. function print_maybe_braced_body(stat, output) {
  2229. if (output.option("braces")) {
  2230. make_block(stat, output);
  2231. } else {
  2232. if (!stat || stat instanceof AST_EmptyStatement)
  2233. output.force_semicolon();
  2234. else if (stat instanceof AST_Let || stat instanceof AST_Const || stat instanceof AST_Class)
  2235. make_block(stat, output);
  2236. else
  2237. stat.print(output);
  2238. }
  2239. }
  2240. function best_of(a) {
  2241. var best = a[0], len = best.length;
  2242. for (var i = 1; i < a.length; ++i) {
  2243. if (a[i].length < len) {
  2244. best = a[i];
  2245. len = best.length;
  2246. }
  2247. }
  2248. return best;
  2249. }
  2250. function make_num(num) {
  2251. var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
  2252. var candidates = [ str ];
  2253. if (Math.floor(num) === num) {
  2254. if (num < 0) {
  2255. candidates.push("-0x" + (-num).toString(16).toLowerCase());
  2256. } else {
  2257. candidates.push("0x" + num.toString(16).toLowerCase());
  2258. }
  2259. }
  2260. var match, len, digits;
  2261. if (match = /^\.0+/.exec(str)) {
  2262. len = match[0].length;
  2263. digits = str.slice(len);
  2264. candidates.push(digits + "e-" + (digits.length + len - 1));
  2265. } else if (match = /0+$/.exec(str)) {
  2266. len = match[0].length;
  2267. candidates.push(str.slice(0, -len) + "e" + len);
  2268. } else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
  2269. candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
  2270. }
  2271. return best_of(candidates);
  2272. }
  2273. function make_block(stmt, output) {
  2274. if (!stmt || stmt instanceof AST_EmptyStatement)
  2275. output.print("{}");
  2276. else if (stmt instanceof AST_BlockStatement)
  2277. stmt.print(output);
  2278. else output.with_block(function() {
  2279. output.indent();
  2280. stmt.print(output);
  2281. output.newline();
  2282. });
  2283. }
  2284. /* -----[ source map generators ]----- */
  2285. function DEFMAP(nodetype, generator) {
  2286. nodetype.forEach(function(nodetype) {
  2287. nodetype.DEFMETHOD("add_source_map", generator);
  2288. });
  2289. }
  2290. DEFMAP([
  2291. // We could easily add info for ALL nodes, but it seems to me that
  2292. // would be quite wasteful, hence this noop in the base class.
  2293. AST_Node,
  2294. // since the label symbol will mark it
  2295. AST_LabeledStatement,
  2296. AST_Toplevel,
  2297. ], noop);
  2298. // XXX: I'm not exactly sure if we need it for all of these nodes,
  2299. // or if we should add even more.
  2300. DEFMAP([
  2301. AST_Array,
  2302. AST_BlockStatement,
  2303. AST_Catch,
  2304. AST_Class,
  2305. AST_Constant,
  2306. AST_Debugger,
  2307. AST_Definitions,
  2308. AST_Directive,
  2309. AST_Finally,
  2310. AST_Jump,
  2311. AST_Lambda,
  2312. AST_New,
  2313. AST_Object,
  2314. AST_StatementWithBody,
  2315. AST_Symbol,
  2316. AST_Switch,
  2317. AST_SwitchBranch,
  2318. AST_TemplateString,
  2319. AST_TemplateSegment,
  2320. AST_Try,
  2321. ], function(output) {
  2322. output.add_mapping(this.start);
  2323. });
  2324. DEFMAP([
  2325. AST_ObjectGetter,
  2326. AST_ObjectSetter,
  2327. AST_PrivateGetter,
  2328. AST_PrivateSetter,
  2329. AST_ConciseMethod,
  2330. AST_PrivateMethod,
  2331. ], function(output) {
  2332. output.add_mapping(this.start, false /*name handled below*/);
  2333. });
  2334. DEFMAP([
  2335. AST_SymbolMethod,
  2336. AST_SymbolPrivateProperty
  2337. ], function(output) {
  2338. const tok_type = this.end && this.end.type;
  2339. if (tok_type === "name" || tok_type === "privatename") {
  2340. output.add_mapping(this.end, this.name);
  2341. } else {
  2342. output.add_mapping(this.end);
  2343. }
  2344. });
  2345. DEFMAP([ AST_ObjectProperty ], function(output) {
  2346. output.add_mapping(this.start, this.key);
  2347. });
  2348. })();
  2349. export {
  2350. OutputStream,
  2351. };