escodegen.js 97 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736
  1. /*
  2. Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
  3. Copyright (C) 2015 Ingvar Stepanyan <me@rreverser.com>
  4. Copyright (C) 2014 Ivan Nikulin <ifaaan@gmail.com>
  5. Copyright (C) 2012-2013 Michael Ficarra <escodegen.copyright@michael.ficarra.me>
  6. Copyright (C) 2012-2013 Mathias Bynens <mathias@qiwi.be>
  7. Copyright (C) 2013 Irakli Gozalishvili <rfobic@gmail.com>
  8. Copyright (C) 2012 Robert Gust-Bardon <donate@robert.gust-bardon.org>
  9. Copyright (C) 2012 John Freeman <jfreeman08@gmail.com>
  10. Copyright (C) 2011-2012 Ariya Hidayat <ariya.hidayat@gmail.com>
  11. Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
  12. Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
  13. Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
  14. Redistribution and use in source and binary forms, with or without
  15. modification, are permitted provided that the following conditions are met:
  16. * Redistributions of source code must retain the above copyright
  17. notice, this list of conditions and the following disclaimer.
  18. * Redistributions in binary form must reproduce the above copyright
  19. notice, this list of conditions and the following disclaimer in the
  20. documentation and/or other materials provided with the distribution.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  25. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  26. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  28. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  30. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. /*global exports:true, require:true, global:true*/
  33. (function () {
  34. 'use strict';
  35. var Syntax,
  36. Precedence,
  37. BinaryPrecedence,
  38. SourceNode,
  39. estraverse,
  40. esutils,
  41. base,
  42. indent,
  43. json,
  44. renumber,
  45. hexadecimal,
  46. quotes,
  47. escapeless,
  48. newline,
  49. space,
  50. parentheses,
  51. semicolons,
  52. safeConcatenation,
  53. directive,
  54. extra,
  55. parse,
  56. sourceMap,
  57. sourceCode,
  58. preserveBlankLines,
  59. FORMAT_MINIFY,
  60. FORMAT_DEFAULTS;
  61. estraverse = require('@javascript-obfuscator/estraverse');
  62. esutils = require('esutils');
  63. Syntax = estraverse.Syntax;
  64. // Generation is done by generateExpression.
  65. function isExpression(node) {
  66. return CodeGenerator.Expression.hasOwnProperty(node.type);
  67. }
  68. // Generation is done by generateStatement.
  69. function isStatement(node) {
  70. return CodeGenerator.Statement.hasOwnProperty(node.type);
  71. }
  72. Precedence = {
  73. Sequence: 0,
  74. Yield: 1,
  75. Assignment: 1,
  76. Conditional: 2,
  77. ArrowFunction: 2,
  78. NullishCoalescing: 3,
  79. LogicalOR: 3,
  80. LogicalAND: 4,
  81. BitwiseOR: 5,
  82. BitwiseXOR: 6,
  83. BitwiseAND: 7,
  84. Equality: 8,
  85. Relational: 9,
  86. BitwiseSHIFT: 10,
  87. Additive: 11,
  88. Multiplicative: 12,
  89. Exponentiation: 13,
  90. Await: 14,
  91. Unary: 14,
  92. Postfix: 15,
  93. OptionalChaining: 16,
  94. Call: 17,
  95. New: 18,
  96. TaggedTemplate: 19,
  97. Member: 20,
  98. Primary: 21
  99. };
  100. BinaryPrecedence = {
  101. '??': Precedence.NullishCoalescing,
  102. '||': Precedence.LogicalOR,
  103. '&&': Precedence.LogicalAND,
  104. '|': Precedence.BitwiseOR,
  105. '^': Precedence.BitwiseXOR,
  106. '&': Precedence.BitwiseAND,
  107. '==': Precedence.Equality,
  108. '!=': Precedence.Equality,
  109. '===': Precedence.Equality,
  110. '!==': Precedence.Equality,
  111. 'is': Precedence.Equality,
  112. 'isnt': Precedence.Equality,
  113. '<': Precedence.Relational,
  114. '>': Precedence.Relational,
  115. '<=': Precedence.Relational,
  116. '>=': Precedence.Relational,
  117. 'in': Precedence.Relational,
  118. 'instanceof': Precedence.Relational,
  119. '<<': Precedence.BitwiseSHIFT,
  120. '>>': Precedence.BitwiseSHIFT,
  121. '>>>': Precedence.BitwiseSHIFT,
  122. '+': Precedence.Additive,
  123. '-': Precedence.Additive,
  124. '*': Precedence.Multiplicative,
  125. '%': Precedence.Multiplicative,
  126. '/': Precedence.Multiplicative,
  127. '**': Precedence.Exponentiation
  128. };
  129. //Flags
  130. var F_ALLOW_IN = 1,
  131. F_ALLOW_CALL = 1 << 1,
  132. F_ALLOW_UNPARATH_NEW = 1 << 2,
  133. F_FUNC_BODY = 1 << 3,
  134. F_DIRECTIVE_CTX = 1 << 4,
  135. F_SEMICOLON_OPT = 1 << 5;
  136. //Expression flag sets
  137. //NOTE: Flag order:
  138. // F_ALLOW_IN
  139. // F_ALLOW_CALL
  140. // F_ALLOW_UNPARATH_NEW
  141. var E_FTT = F_ALLOW_CALL | F_ALLOW_UNPARATH_NEW,
  142. E_TTF = F_ALLOW_IN | F_ALLOW_CALL,
  143. E_TTT = F_ALLOW_IN | F_ALLOW_CALL | F_ALLOW_UNPARATH_NEW,
  144. E_TFF = F_ALLOW_IN,
  145. E_FFT = F_ALLOW_UNPARATH_NEW,
  146. E_TFT = F_ALLOW_IN | F_ALLOW_UNPARATH_NEW;
  147. //Statement flag sets
  148. //NOTE: Flag order:
  149. // F_ALLOW_IN
  150. // F_FUNC_BODY
  151. // F_DIRECTIVE_CTX
  152. // F_SEMICOLON_OPT
  153. var S_TFFF = F_ALLOW_IN,
  154. S_TFFT = F_ALLOW_IN | F_SEMICOLON_OPT,
  155. S_FFFF = 0x00,
  156. S_TFTF = F_ALLOW_IN | F_DIRECTIVE_CTX,
  157. S_TTFF = F_ALLOW_IN | F_FUNC_BODY;
  158. function getDefaultOptions() {
  159. // default options
  160. return {
  161. indent: null,
  162. base: null,
  163. parse: null,
  164. comment: false,
  165. format: {
  166. indent: {
  167. style: ' ',
  168. base: 0,
  169. adjustMultilineComment: false
  170. },
  171. newline: '\n',
  172. space: ' ',
  173. json: false,
  174. renumber: false,
  175. hexadecimal: false,
  176. quotes: 'single',
  177. escapeless: false,
  178. compact: false,
  179. parentheses: true,
  180. semicolons: true,
  181. safeConcatenation: false,
  182. preserveBlankLines: false
  183. },
  184. moz: {
  185. comprehensionExpressionStartsWithAssignment: false,
  186. starlessGenerator: false
  187. },
  188. sourceMap: null,
  189. sourceMapRoot: null,
  190. sourceMapWithCode: false,
  191. directive: false,
  192. raw: true,
  193. verbatim: null,
  194. sourceCode: null
  195. };
  196. }
  197. function stringRepeat(str, num) {
  198. var result = '';
  199. for (num |= 0; num > 0; num >>>= 1, str += str) {
  200. if (num & 1) {
  201. result += str;
  202. }
  203. }
  204. return result;
  205. }
  206. function hasLineTerminator(str) {
  207. return (/[\r\n]/g).test(str);
  208. }
  209. function endsWithLineTerminator(str) {
  210. var len = str.length;
  211. return len && esutils.code.isLineTerminator(str.charCodeAt(len - 1));
  212. }
  213. function merge(target, override) {
  214. var key;
  215. for (key in override) {
  216. if (override.hasOwnProperty(key)) {
  217. target[key] = override[key];
  218. }
  219. }
  220. return target;
  221. }
  222. function updateDeeply(target, override) {
  223. var key, val;
  224. function isHashObject(target) {
  225. return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
  226. }
  227. for (key in override) {
  228. if (override.hasOwnProperty(key)) {
  229. val = override[key];
  230. if (isHashObject(val)) {
  231. if (isHashObject(target[key])) {
  232. updateDeeply(target[key], val);
  233. } else {
  234. target[key] = updateDeeply({}, val);
  235. }
  236. } else {
  237. target[key] = val;
  238. }
  239. }
  240. }
  241. return target;
  242. }
  243. function generateNumber(value) {
  244. var result, point, temp, exponent, pos;
  245. if (value !== value) {
  246. throw new Error('Numeric literal whose value is NaN');
  247. }
  248. if (value < 0 || (value === 0 && 1 / value < 0)) {
  249. throw new Error('Numeric literal whose value is negative');
  250. }
  251. if (value === 1 / 0) {
  252. return json ? 'null' : renumber ? '1e400' : '1e+400';
  253. }
  254. result = '' + value;
  255. if (!renumber || result.length < 3) {
  256. return result;
  257. }
  258. point = result.indexOf('.');
  259. if (!json && result.charCodeAt(0) === 0x30 /* 0 */ && point === 1) {
  260. point = 0;
  261. result = result.slice(1);
  262. }
  263. temp = result;
  264. result = result.replace('e+', 'e');
  265. exponent = 0;
  266. if ((pos = temp.indexOf('e')) > 0) {
  267. exponent = +temp.slice(pos + 1);
  268. temp = temp.slice(0, pos);
  269. }
  270. if (point >= 0) {
  271. exponent -= temp.length - point - 1;
  272. temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
  273. }
  274. pos = 0;
  275. while (temp.charCodeAt(temp.length + pos - 1) === 0x30 /* 0 */) {
  276. --pos;
  277. }
  278. if (pos !== 0) {
  279. exponent -= pos;
  280. temp = temp.slice(0, pos);
  281. }
  282. if (exponent !== 0) {
  283. temp += 'e' + exponent;
  284. }
  285. if ((temp.length < result.length ||
  286. (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
  287. +temp === value) {
  288. result = temp;
  289. }
  290. return result;
  291. }
  292. // Generate valid RegExp expression.
  293. // This function is based on https://github.com/Constellation/iv Engine
  294. function escapeRegExpCharacter(ch, previousIsBackslash) {
  295. // not handling '\' and handling \u2028 or \u2029 to unicode escape sequence
  296. if ((ch & ~1) === 0x2028) {
  297. return (previousIsBackslash ? 'u' : '\\u') + ((ch === 0x2028) ? '2028' : '2029');
  298. } else if (ch === 10 || ch === 13) { // \n, \r
  299. return (previousIsBackslash ? '' : '\\') + ((ch === 10) ? 'n' : 'r');
  300. }
  301. return String.fromCharCode(ch);
  302. }
  303. function generateRegExp(reg) {
  304. var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash;
  305. result = reg.toString();
  306. if (reg.source) {
  307. // extract flag from toString result
  308. match = result.match(/\/([^/]*)$/);
  309. if (!match) {
  310. return result;
  311. }
  312. flags = match[1];
  313. result = '';
  314. characterInBrack = false;
  315. previousIsBackslash = false;
  316. for (i = 0, iz = reg.source.length; i < iz; ++i) {
  317. ch = reg.source.charCodeAt(i);
  318. if (!previousIsBackslash) {
  319. if (characterInBrack) {
  320. if (ch === 93) { // ]
  321. characterInBrack = false;
  322. }
  323. } else {
  324. if (ch === 47) { // /
  325. result += '\\';
  326. } else if (ch === 91) { // [
  327. characterInBrack = true;
  328. }
  329. }
  330. result += escapeRegExpCharacter(ch, previousIsBackslash);
  331. previousIsBackslash = ch === 92; // \
  332. } else {
  333. // if new RegExp("\\\n') is provided, create /\n/
  334. result += escapeRegExpCharacter(ch, previousIsBackslash);
  335. // prevent like /\\[/]/
  336. previousIsBackslash = false;
  337. }
  338. }
  339. return '/' + result + '/' + flags;
  340. }
  341. return result;
  342. }
  343. function escapeAllowedCharacter(code, next) {
  344. var hex;
  345. if (code === 0x08 /* \b */) {
  346. return '\\b';
  347. }
  348. if (code === 0x0C /* \f */) {
  349. return '\\f';
  350. }
  351. if (code === 0x09 /* \t */) {
  352. return '\\t';
  353. }
  354. hex = code.toString(16).toUpperCase();
  355. if (json || code > 0xFF) {
  356. return '\\u' + '0000'.slice(hex.length) + hex;
  357. } else if (code === 0x0000 && !esutils.code.isDecimalDigit(next)) {
  358. return '\\0';
  359. } else if (code === 0x000B /* \v */) { // '\v'
  360. return '\\x0B';
  361. } else {
  362. return '\\x' + '00'.slice(hex.length) + hex;
  363. }
  364. }
  365. function escapeDisallowedCharacter(code) {
  366. if (code === 0x5C /* \ */) {
  367. return '\\\\';
  368. }
  369. if (code === 0x0A /* \n */) {
  370. return '\\n';
  371. }
  372. if (code === 0x0D /* \r */) {
  373. return '\\r';
  374. }
  375. if (code === 0x2028) {
  376. return '\\u2028';
  377. }
  378. if (code === 0x2029) {
  379. return '\\u2029';
  380. }
  381. throw new Error('Incorrectly classified character');
  382. }
  383. function escapeDirective(str) {
  384. var i, iz, code, quote;
  385. quote = quotes === 'double' ? '"' : '\'';
  386. for (i = 0, iz = str.length; i < iz; ++i) {
  387. code = str.charCodeAt(i);
  388. if (code === 0x27 /* ' */) {
  389. quote = '"';
  390. break;
  391. } else if (code === 0x22 /* " */) {
  392. quote = '\'';
  393. break;
  394. } else if (code === 0x5C /* \ */) {
  395. ++i;
  396. }
  397. }
  398. return quote + str + quote;
  399. }
  400. function escapeString(str) {
  401. var result = '', i, len, code, singleQuotes = 0, doubleQuotes = 0, single, quote;
  402. for (i = 0, len = str.length; i < len; ++i) {
  403. code = str.charCodeAt(i);
  404. if (code === 0x27 /* ' */) {
  405. ++singleQuotes;
  406. } else if (code === 0x22 /* " */) {
  407. ++doubleQuotes;
  408. } else if (code === 0x2F /* / */ && json) {
  409. result += '\\';
  410. } else if (esutils.code.isLineTerminator(code) || code === 0x5C /* \ */) {
  411. result += escapeDisallowedCharacter(code);
  412. continue;
  413. } else if (!esutils.code.isIdentifierPartES5(code) && (json && code < 0x20 /* SP */ || !json && !escapeless && (code < 0x20 /* SP */ || code > 0x7E /* ~ */))) {
  414. result += escapeAllowedCharacter(code, str.charCodeAt(i + 1));
  415. continue;
  416. }
  417. result += String.fromCharCode(code);
  418. }
  419. single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes));
  420. quote = single ? '\'' : '"';
  421. if (!(single ? singleQuotes : doubleQuotes)) {
  422. return quote + result + quote;
  423. }
  424. str = result;
  425. result = quote;
  426. for (i = 0, len = str.length; i < len; ++i) {
  427. code = str.charCodeAt(i);
  428. if ((code === 0x27 /* ' */ && single) || (code === 0x22 /* " */ && !single)) {
  429. result += '\\';
  430. }
  431. result += String.fromCharCode(code);
  432. }
  433. return result + quote;
  434. }
  435. /**
  436. * flatten an array to a string, where the array can contain
  437. * either strings or nested arrays
  438. */
  439. function flattenToString(arr) {
  440. var i, iz, elem, result = '';
  441. for (i = 0, iz = arr.length; i < iz; ++i) {
  442. elem = arr[i];
  443. result += Array.isArray(elem) ? flattenToString(elem) : elem;
  444. }
  445. return result;
  446. }
  447. /**
  448. * convert generated to a SourceNode when source maps are enabled.
  449. */
  450. function toSourceNodeWhenNeeded(generated, node) {
  451. if (!sourceMap) {
  452. // with no source maps, generated is either an
  453. // array or a string. if an array, flatten it.
  454. // if a string, just return it
  455. if (Array.isArray(generated)) {
  456. return flattenToString(generated);
  457. } else {
  458. return generated;
  459. }
  460. }
  461. if (node == null) {
  462. if (generated instanceof SourceNode) {
  463. return generated;
  464. } else {
  465. node = {};
  466. }
  467. }
  468. if (node.loc == null) {
  469. return new SourceNode(null, null, sourceMap, generated, node.name || null);
  470. }
  471. return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated, node.name || null);
  472. }
  473. function noEmptySpace() {
  474. return (space) ? space : ' ';
  475. }
  476. function join(left, right) {
  477. var leftSource,
  478. rightSource,
  479. leftCharCode,
  480. rightCharCode;
  481. leftSource = toSourceNodeWhenNeeded(left).toString();
  482. if (leftSource.length === 0) {
  483. return [right];
  484. }
  485. rightSource = toSourceNodeWhenNeeded(right).toString();
  486. if (rightSource.length === 0) {
  487. return [left];
  488. }
  489. leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
  490. rightCharCode = rightSource.charCodeAt(0);
  491. if ((leftCharCode === 0x2B /* + */ || leftCharCode === 0x2D /* - */) && leftCharCode === rightCharCode ||
  492. esutils.code.isIdentifierPartES5(leftCharCode) && esutils.code.isIdentifierPartES5(rightCharCode) ||
  493. leftCharCode === 0x2F /* / */ && rightCharCode === 0x69 /* i */) { // infix word operators all start with `i`
  494. return [left, noEmptySpace(), right];
  495. } else if (esutils.code.isWhiteSpace(leftCharCode) || esutils.code.isLineTerminator(leftCharCode) ||
  496. esutils.code.isWhiteSpace(rightCharCode) || esutils.code.isLineTerminator(rightCharCode)) {
  497. return [left, right];
  498. }
  499. return [left, space, right];
  500. }
  501. function addIndent(stmt) {
  502. return [base, stmt];
  503. }
  504. function withIndent(fn) {
  505. var previousBase;
  506. previousBase = base;
  507. base += indent;
  508. fn(base);
  509. base = previousBase;
  510. }
  511. function calculateSpaces(str) {
  512. var i;
  513. for (i = str.length - 1; i >= 0; --i) {
  514. if (esutils.code.isLineTerminator(str.charCodeAt(i))) {
  515. break;
  516. }
  517. }
  518. return (str.length - 1) - i;
  519. }
  520. function adjustMultilineComment(value, specialBase) {
  521. var array, i, len, line, j, spaces, previousBase, sn;
  522. array = value.split(/\r\n|[\r\n]/);
  523. spaces = Number.MAX_VALUE;
  524. // first line doesn't have indentation
  525. for (i = 1, len = array.length; i < len; ++i) {
  526. line = array[i];
  527. j = 0;
  528. while (j < line.length && esutils.code.isWhiteSpace(line.charCodeAt(j))) {
  529. ++j;
  530. }
  531. if (spaces > j) {
  532. spaces = j;
  533. }
  534. }
  535. if (typeof specialBase !== 'undefined') {
  536. // pattern like
  537. // {
  538. // var t = 20; /*
  539. // * this is comment
  540. // */
  541. // }
  542. previousBase = base;
  543. if (array[1][spaces] === '*') {
  544. specialBase += ' ';
  545. }
  546. base = specialBase;
  547. } else {
  548. if (spaces & 1) {
  549. // /*
  550. // *
  551. // */
  552. // If spaces are odd number, above pattern is considered.
  553. // We waste 1 space.
  554. --spaces;
  555. }
  556. previousBase = base;
  557. }
  558. for (i = 1, len = array.length; i < len; ++i) {
  559. sn = toSourceNodeWhenNeeded(addIndent(array[i].slice(spaces)));
  560. array[i] = sourceMap ? sn.join('') : sn;
  561. }
  562. base = previousBase;
  563. return array.join('\n');
  564. }
  565. function generateComment(comment, specialBase) {
  566. if (comment.type === 'Line') {
  567. if (endsWithLineTerminator(comment.value)) {
  568. return '//' + comment.value;
  569. } else {
  570. // Always use LineTerminator
  571. var result = '//' + comment.value;
  572. if (!preserveBlankLines) {
  573. result += '\n';
  574. }
  575. return result;
  576. }
  577. }
  578. if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
  579. return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
  580. }
  581. return '/*' + comment.value + '*/';
  582. }
  583. function addComments(stmt, result) {
  584. var i, len, comment, save, tailingToStatement, specialBase, fragment,
  585. extRange, range, prevRange, prefix, infix, suffix, count;
  586. if (stmt.leadingComments && stmt.leadingComments.length > 0) {
  587. save = result;
  588. if (preserveBlankLines) {
  589. comment = stmt.leadingComments[0];
  590. result = [];
  591. extRange = comment.extendedRange;
  592. range = comment.range;
  593. prefix = sourceCode.substring(extRange[0], range[0]);
  594. count = (prefix.match(/\n/g) || []).length;
  595. if (count > 0) {
  596. result.push(stringRepeat('\n', count));
  597. result.push(addIndent(generateComment(comment)));
  598. } else {
  599. result.push(prefix);
  600. result.push(generateComment(comment));
  601. }
  602. prevRange = range;
  603. for (i = 1, len = stmt.leadingComments.length; i < len; i++) {
  604. comment = stmt.leadingComments[i];
  605. range = comment.range;
  606. infix = sourceCode.substring(prevRange[1], range[0]);
  607. count = (infix.match(/\n/g) || []).length;
  608. result.push(stringRepeat('\n', count));
  609. result.push(addIndent(generateComment(comment)));
  610. prevRange = range;
  611. }
  612. suffix = sourceCode.substring(range[1], extRange[1]);
  613. count = (suffix.match(/\n/g) || []).length;
  614. result.push(stringRepeat('\n', count));
  615. } else {
  616. comment = stmt.leadingComments[0];
  617. result = [];
  618. if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) {
  619. result.push('\n');
  620. }
  621. result.push(generateComment(comment));
  622. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  623. result.push('\n');
  624. }
  625. for (i = 1, len = stmt.leadingComments.length; i < len; ++i) {
  626. comment = stmt.leadingComments[i];
  627. fragment = [generateComment(comment)];
  628. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  629. fragment.push('\n');
  630. }
  631. result.push(addIndent(fragment));
  632. }
  633. }
  634. result.push(addIndent(save));
  635. }
  636. if (stmt.trailingComments) {
  637. if (preserveBlankLines) {
  638. comment = stmt.trailingComments[0];
  639. extRange = comment.extendedRange;
  640. range = comment.range;
  641. prefix = sourceCode.substring(extRange[0], range[0]);
  642. count = (prefix.match(/\n/g) || []).length;
  643. if (count > 0) {
  644. result.push(stringRepeat('\n', count));
  645. result.push(addIndent(generateComment(comment)));
  646. } else {
  647. result.push(prefix);
  648. result.push(generateComment(comment));
  649. }
  650. } else {
  651. tailingToStatement = !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString());
  652. specialBase = stringRepeat(' ', calculateSpaces(toSourceNodeWhenNeeded([base, result, indent]).toString()));
  653. for (i = 0, len = stmt.trailingComments.length; i < len; ++i) {
  654. comment = stmt.trailingComments[i];
  655. if (tailingToStatement) {
  656. // We assume target like following script
  657. //
  658. // var t = 20; /**
  659. // * This is comment of t
  660. // */
  661. if (i === 0) {
  662. // first case
  663. result = [result, indent];
  664. } else {
  665. result = [result, specialBase];
  666. }
  667. result.push(generateComment(comment, specialBase));
  668. } else {
  669. result = [result, addIndent(generateComment(comment))];
  670. }
  671. if (i !== len - 1 && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  672. result = [result, '\n'];
  673. }
  674. }
  675. }
  676. }
  677. return result;
  678. }
  679. function generateBlankLines(start, end, result) {
  680. var j, newlineCount = 0;
  681. for (j = start; j < end; j++) {
  682. if (sourceCode[j] === '\n') {
  683. newlineCount++;
  684. }
  685. }
  686. for (j = 1; j < newlineCount; j++) {
  687. result.push(newline);
  688. }
  689. }
  690. function parenthesize(text, current, should) {
  691. if (current < should) {
  692. return ['(', text, ')'];
  693. }
  694. return text;
  695. }
  696. function generateVerbatimString(string) {
  697. var i, iz, result;
  698. result = string.split(/\r\n|\n/);
  699. for (i = 1, iz = result.length; i < iz; i++) {
  700. result[i] = newline + base + result[i];
  701. }
  702. return result;
  703. }
  704. function generateVerbatim(expr, precedence) {
  705. var verbatim, result, prec;
  706. verbatim = expr[extra.verbatim];
  707. if (typeof verbatim === 'string') {
  708. result = parenthesize(generateVerbatimString(verbatim), Precedence.Sequence, precedence);
  709. } else {
  710. // verbatim is object
  711. result = generateVerbatimString(verbatim.content);
  712. prec = (verbatim.precedence != null) ? verbatim.precedence : Precedence.Sequence;
  713. result = parenthesize(result, prec, precedence);
  714. }
  715. return toSourceNodeWhenNeeded(result, expr);
  716. }
  717. function CodeGenerator() {
  718. }
  719. // Helpers.
  720. CodeGenerator.prototype.maybeBlock = function(stmt, flags) {
  721. var result, noLeadingComment, that = this;
  722. noLeadingComment = !extra.comment || !stmt.leadingComments;
  723. if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
  724. return [space, this.generateStatement(stmt, flags)];
  725. }
  726. if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
  727. return ';';
  728. }
  729. withIndent(function () {
  730. result = [
  731. newline,
  732. addIndent(that.generateStatement(stmt, flags))
  733. ];
  734. });
  735. return result;
  736. };
  737. CodeGenerator.prototype.maybeBlockSuffix = function (stmt, result) {
  738. var ends = endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString());
  739. if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) {
  740. return [result, space];
  741. }
  742. if (ends) {
  743. return [result, base];
  744. }
  745. return [result, newline, base];
  746. };
  747. function generateIdentifier(node) {
  748. var identifierName = node.name;
  749. if (node.type === Syntax.PrivateIdentifier) {
  750. identifierName = '#' + identifierName;
  751. }
  752. return toSourceNodeWhenNeeded(identifierName, node);
  753. }
  754. function generateAsyncPrefix(node, spaceRequired) {
  755. return node.async ? 'async' + (spaceRequired ? noEmptySpace() : space) : '';
  756. }
  757. function generateStarSuffix(node) {
  758. var isGenerator = node.generator && !extra.moz.starlessGenerator;
  759. return isGenerator ? '*' + space : '';
  760. }
  761. function generateMethodPrefix(prop) {
  762. var func = prop.value, prefix = '';
  763. if (func.async) {
  764. prefix += generateAsyncPrefix(func, !prop.computed);
  765. }
  766. if (func.generator) {
  767. // avoid space before method name
  768. prefix += generateStarSuffix(func) ? '*' : '';
  769. }
  770. return prefix;
  771. }
  772. CodeGenerator.prototype.generatePattern = function (node, precedence, flags) {
  773. if (node.type === Syntax.Identifier) {
  774. return generateIdentifier(node);
  775. }
  776. return this.generateExpression(node, precedence, flags);
  777. };
  778. CodeGenerator.prototype.generateFunctionParams = function (node) {
  779. var i, iz, result, hasDefault;
  780. hasDefault = false;
  781. if (node.type === Syntax.ArrowFunctionExpression &&
  782. !node.rest && (!node.defaults || node.defaults.length === 0) &&
  783. node.params.length === 1 && node.params[0].type === Syntax.Identifier) {
  784. // arg => { } case
  785. result = [generateAsyncPrefix(node, true), generateIdentifier(node.params[0])];
  786. } else {
  787. result = node.type === Syntax.ArrowFunctionExpression ? [generateAsyncPrefix(node, false)] : [];
  788. result.push('(');
  789. if (node.defaults) {
  790. hasDefault = true;
  791. }
  792. for (i = 0, iz = node.params.length; i < iz; ++i) {
  793. if (hasDefault && node.defaults[i]) {
  794. // Handle default values.
  795. result.push(this.generateAssignment(node.params[i], node.defaults[i], '=', Precedence.Assignment, E_TTT));
  796. } else {
  797. result.push(this.generatePattern(node.params[i], Precedence.Assignment, E_TTT));
  798. }
  799. if (i + 1 < iz) {
  800. result.push(',' + space);
  801. }
  802. }
  803. if (node.rest) {
  804. if (node.params.length) {
  805. result.push(',' + space);
  806. }
  807. result.push('...');
  808. result.push(generateIdentifier(node.rest));
  809. }
  810. result.push(')');
  811. }
  812. return result;
  813. };
  814. CodeGenerator.prototype.generateFunctionBody = function (node) {
  815. var result, expr;
  816. result = this.generateFunctionParams(node);
  817. if (node.type === Syntax.ArrowFunctionExpression) {
  818. result.push(space);
  819. result.push('=>');
  820. }
  821. if (node.expression) {
  822. result.push(space);
  823. expr = this.generateExpression(node.body, Precedence.Assignment, E_TTT);
  824. if (expr.toString().charAt(0) === '{') {
  825. expr = ['(', expr, ')'];
  826. }
  827. result.push(expr);
  828. } else {
  829. result.push(this.maybeBlock(node.body, S_TTFF));
  830. }
  831. return result;
  832. };
  833. CodeGenerator.prototype.generateIterationForStatement = function (operator, stmt, flags) {
  834. var result = ['for' + (stmt.await ? noEmptySpace() + 'await' : '') + space + '('], that = this;
  835. withIndent(function () {
  836. if (stmt.left.type === Syntax.VariableDeclaration) {
  837. withIndent(function () {
  838. result.push(stmt.left.kind + noEmptySpace());
  839. result.push(that.generateStatement(stmt.left.declarations[0], S_FFFF));
  840. });
  841. } else {
  842. result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
  843. }
  844. result = join(result, operator);
  845. result = [join(
  846. result,
  847. that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
  848. ), ')'];
  849. });
  850. result.push(this.maybeBlock(stmt.body, flags));
  851. return result;
  852. };
  853. CodeGenerator.prototype.generatePropertyKey = function (expr, computed) {
  854. var result = [];
  855. if (computed) {
  856. result.push('[');
  857. }
  858. result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
  859. if (computed) {
  860. result.push(']');
  861. }
  862. return result;
  863. };
  864. CodeGenerator.prototype.generateAssignment = function (left, right, operator, precedence, flags) {
  865. if (Precedence.Assignment < precedence) {
  866. flags |= F_ALLOW_IN;
  867. }
  868. return parenthesize(
  869. [
  870. this.generateExpression(left, Precedence.Call, flags),
  871. space + operator + space,
  872. this.generateExpression(right, Precedence.Assignment, flags)
  873. ],
  874. Precedence.Assignment,
  875. precedence
  876. );
  877. };
  878. CodeGenerator.prototype.semicolon = function (flags) {
  879. if (!semicolons && flags & F_SEMICOLON_OPT) {
  880. return '';
  881. }
  882. return ';';
  883. };
  884. // Statements.
  885. CodeGenerator.Statement = {
  886. BlockStatement: function (stmt, flags) {
  887. var range, content, result = ['{', newline], that = this;
  888. withIndent(function () {
  889. // handle functions without any code
  890. if (stmt.body.length === 0 && preserveBlankLines) {
  891. range = stmt.range;
  892. if (range[1] - range[0] > 2) {
  893. content = sourceCode.substring(range[0] + 1, range[1] - 1);
  894. if (content[0] === '\n') {
  895. result = ['{'];
  896. }
  897. result.push(content);
  898. }
  899. }
  900. var i, iz, fragment, bodyFlags;
  901. bodyFlags = S_TFFF;
  902. if (flags & F_FUNC_BODY) {
  903. bodyFlags |= F_DIRECTIVE_CTX;
  904. }
  905. for (i = 0, iz = stmt.body.length; i < iz; ++i) {
  906. if (preserveBlankLines) {
  907. // handle spaces before the first line
  908. if (i === 0) {
  909. if (stmt.body[0].leadingComments) {
  910. range = stmt.body[0].leadingComments[0].extendedRange;
  911. content = sourceCode.substring(range[0], range[1]);
  912. if (content[0] === '\n') {
  913. result = ['{'];
  914. }
  915. }
  916. if (!stmt.body[0].leadingComments) {
  917. generateBlankLines(stmt.range[0], stmt.body[0].range[0], result);
  918. }
  919. }
  920. // handle spaces between lines
  921. if (i > 0) {
  922. if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
  923. generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
  924. }
  925. }
  926. }
  927. if (i === iz - 1) {
  928. bodyFlags |= F_SEMICOLON_OPT;
  929. }
  930. if (stmt.body[i].leadingComments && preserveBlankLines) {
  931. fragment = that.generateStatement(stmt.body[i], bodyFlags);
  932. } else {
  933. fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
  934. }
  935. result.push(fragment);
  936. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  937. if (preserveBlankLines && i < iz - 1) {
  938. // don't add a new line if there are leading coments
  939. // in the next statement
  940. if (!stmt.body[i + 1].leadingComments) {
  941. result.push(newline);
  942. }
  943. } else {
  944. result.push(newline);
  945. }
  946. }
  947. if (preserveBlankLines) {
  948. // handle spaces after the last line
  949. if (i === iz - 1) {
  950. if (!stmt.body[i].trailingComments) {
  951. generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
  952. }
  953. }
  954. }
  955. }
  956. });
  957. result.push(addIndent('}'));
  958. return result;
  959. },
  960. BreakStatement: function (stmt, flags) {
  961. if (stmt.label) {
  962. return 'break ' + stmt.label.name + this.semicolon(flags);
  963. }
  964. return 'break' + this.semicolon(flags);
  965. },
  966. ContinueStatement: function (stmt, flags) {
  967. if (stmt.label) {
  968. return 'continue ' + stmt.label.name + this.semicolon(flags);
  969. }
  970. return 'continue' + this.semicolon(flags);
  971. },
  972. ClassBody: function (stmt, flags) {
  973. var result = [ '{', newline], that = this;
  974. withIndent(function (indent) {
  975. var i, iz;
  976. for (i = 0, iz = stmt.body.length; i < iz; ++i) {
  977. result.push(indent);
  978. result.push(that.generateExpression(stmt.body[i], Precedence.Sequence, E_TTT));
  979. if (i + 1 < iz) {
  980. result.push(newline);
  981. }
  982. }
  983. });
  984. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  985. result.push(newline);
  986. }
  987. result.push(base);
  988. result.push('}');
  989. return result;
  990. },
  991. ClassDeclaration: function (stmt, flags) {
  992. var result, fragment;
  993. result = ['class'];
  994. if (stmt.id) {
  995. result = join(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
  996. }
  997. if (stmt.superClass) {
  998. fragment = join('extends', this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
  999. result = join(result, fragment);
  1000. }
  1001. result.push(space);
  1002. result.push(this.generateStatement(stmt.body, S_TFFT));
  1003. return result;
  1004. },
  1005. DirectiveStatement: function (stmt, flags) {
  1006. if (extra.raw && stmt.raw) {
  1007. return stmt.raw + this.semicolon(flags);
  1008. }
  1009. return escapeDirective(stmt.directive) + this.semicolon(flags);
  1010. },
  1011. DoWhileStatement: function (stmt, flags) {
  1012. // Because `do 42 while (cond)` is Syntax Error. We need semicolon.
  1013. var result = join('do', this.maybeBlock(stmt.body, S_TFFF));
  1014. result = this.maybeBlockSuffix(stmt.body, result);
  1015. return join(result, [
  1016. 'while' + space + '(',
  1017. this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
  1018. ')' + this.semicolon(flags)
  1019. ]);
  1020. },
  1021. CatchClause: function (stmt, flags) {
  1022. var result, that = this;
  1023. withIndent(function () {
  1024. var guard;
  1025. if (stmt.param) {
  1026. result = [
  1027. 'catch' + space + '(',
  1028. that.generateExpression(stmt.param, Precedence.Sequence, E_TTT),
  1029. ')'
  1030. ];
  1031. if (stmt.guard) {
  1032. guard = that.generateExpression(stmt.guard, Precedence.Sequence, E_TTT);
  1033. result.splice(2, 0, ' if ', guard);
  1034. }
  1035. } else {
  1036. result = ['catch'];
  1037. }
  1038. });
  1039. result.push(this.maybeBlock(stmt.body, S_TFFF));
  1040. return result;
  1041. },
  1042. DebuggerStatement: function (stmt, flags) {
  1043. return 'debugger' + this.semicolon(flags);
  1044. },
  1045. EmptyStatement: function (stmt, flags) {
  1046. return ';';
  1047. },
  1048. ExportDefaultDeclaration: function (stmt, flags) {
  1049. var result = [ 'export' ], bodyFlags;
  1050. bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF;
  1051. // export default HoistableDeclaration[Default]
  1052. // export default AssignmentExpression[In] ;
  1053. result = join(result, 'default');
  1054. if (isStatement(stmt.declaration)) {
  1055. result = join(result, this.generateStatement(stmt.declaration, bodyFlags));
  1056. } else {
  1057. result = join(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
  1058. }
  1059. return result;
  1060. },
  1061. ExportNamedDeclaration: function (stmt, flags) {
  1062. var result = [ 'export' ], bodyFlags, that = this;
  1063. bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF;
  1064. // export VariableStatement
  1065. // export Declaration[Default]
  1066. if (stmt.declaration) {
  1067. return join(result, this.generateStatement(stmt.declaration, bodyFlags));
  1068. }
  1069. // export ExportClause[NoReference] FromClause ;
  1070. // export ExportClause ;
  1071. if (stmt.specifiers) {
  1072. if (stmt.specifiers.length === 0) {
  1073. result = join(result, '{' + space + '}');
  1074. } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
  1075. result = join(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
  1076. } else {
  1077. result = join(result, '{');
  1078. withIndent(function (indent) {
  1079. var i, iz;
  1080. result.push(newline);
  1081. for (i = 0, iz = stmt.specifiers.length; i < iz; ++i) {
  1082. result.push(indent);
  1083. result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT));
  1084. if (i + 1 < iz) {
  1085. result.push(',' + newline);
  1086. }
  1087. }
  1088. });
  1089. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  1090. result.push(newline);
  1091. }
  1092. result.push(base + '}');
  1093. }
  1094. if (stmt.source) {
  1095. result = join(result, [
  1096. 'from' + space,
  1097. // ModuleSpecifier
  1098. this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
  1099. this.semicolon(flags)
  1100. ]);
  1101. } else {
  1102. result.push(this.semicolon(flags));
  1103. }
  1104. }
  1105. return result;
  1106. },
  1107. ExportAllDeclaration: function (stmt, flags) {
  1108. // export * FromClause ;
  1109. var result = [
  1110. 'export' + space,
  1111. '*' + space
  1112. ];
  1113. if (stmt.exported) {
  1114. result.push('as ' + stmt.exported.name + ' ');
  1115. }
  1116. result = join(result, [
  1117. 'from' + space,
  1118. // ModuleSpecifier
  1119. this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
  1120. this.semicolon(flags)
  1121. ]);
  1122. return result;
  1123. },
  1124. ExpressionStatement: function (stmt, flags) {
  1125. var result, fragment;
  1126. function isClassPrefixed(fragment) {
  1127. var code;
  1128. if (fragment.slice(0, 5) !== 'class') {
  1129. return false;
  1130. }
  1131. code = fragment.charCodeAt(5);
  1132. return code === 0x7B /* '{' */ || esutils.code.isWhiteSpace(code) || esutils.code.isLineTerminator(code);
  1133. }
  1134. function isFunctionPrefixed(fragment) {
  1135. var code;
  1136. if (fragment.slice(0, 8) !== 'function') {
  1137. return false;
  1138. }
  1139. code = fragment.charCodeAt(8);
  1140. return code === 0x28 /* '(' */ || esutils.code.isWhiteSpace(code) || code === 0x2A /* '*' */ || esutils.code.isLineTerminator(code);
  1141. }
  1142. function isAsyncPrefixed(fragment) {
  1143. var code, i, iz;
  1144. if (fragment.slice(0, 5) !== 'async') {
  1145. return false;
  1146. }
  1147. if (!esutils.code.isWhiteSpace(fragment.charCodeAt(5))) {
  1148. return false;
  1149. }
  1150. for (i = 6, iz = fragment.length; i < iz; ++i) {
  1151. if (!esutils.code.isWhiteSpace(fragment.charCodeAt(i))) {
  1152. break;
  1153. }
  1154. }
  1155. if (i === iz) {
  1156. return false;
  1157. }
  1158. if (fragment.slice(i, i + 8) !== 'function') {
  1159. return false;
  1160. }
  1161. code = fragment.charCodeAt(i + 8);
  1162. return code === 0x28 /* '(' */ || esutils.code.isWhiteSpace(code) || code === 0x2A /* '*' */ || esutils.code.isLineTerminator(code);
  1163. }
  1164. result = [this.generateExpression(stmt.expression, Precedence.Sequence, E_TTT)];
  1165. // 12.4 '{', 'function', 'class' is not allowed in this position.
  1166. // wrap expression with parentheses
  1167. fragment = toSourceNodeWhenNeeded(result).toString();
  1168. if (fragment.charCodeAt(0) === 0x7B /* '{' */ || // ObjectExpression
  1169. isClassPrefixed(fragment) ||
  1170. isFunctionPrefixed(fragment) ||
  1171. isAsyncPrefixed(fragment) ||
  1172. (directive && (flags & F_DIRECTIVE_CTX) && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) {
  1173. result = ['(', result, ')' + this.semicolon(flags)];
  1174. } else {
  1175. result.push(this.semicolon(flags));
  1176. }
  1177. return result;
  1178. },
  1179. ImportDeclaration: function (stmt, flags) {
  1180. // ES6: 15.2.1 valid import declarations:
  1181. // - import ImportClause FromClause ;
  1182. // - import ModuleSpecifier ;
  1183. var result, cursor, that = this;
  1184. // If no ImportClause is present,
  1185. // this should be `import ModuleSpecifier` so skip `from`
  1186. // ModuleSpecifier is StringLiteral.
  1187. if (stmt.specifiers.length === 0) {
  1188. // import ModuleSpecifier ;
  1189. return [
  1190. 'import',
  1191. space,
  1192. // ModuleSpecifier
  1193. this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
  1194. this.semicolon(flags)
  1195. ];
  1196. }
  1197. // import ImportClause FromClause ;
  1198. result = [
  1199. 'import'
  1200. ];
  1201. cursor = 0;
  1202. // ImportedBinding
  1203. if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
  1204. result = join(result, [
  1205. this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
  1206. ]);
  1207. ++cursor;
  1208. }
  1209. if (stmt.specifiers[cursor]) {
  1210. if (cursor !== 0) {
  1211. result.push(',');
  1212. }
  1213. if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
  1214. // NameSpaceImport
  1215. result = join(result, [
  1216. space,
  1217. this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
  1218. ]);
  1219. } else {
  1220. // NamedImports
  1221. result.push(space + '{');
  1222. if ((stmt.specifiers.length - cursor) === 1) {
  1223. // import { ... } from "...";
  1224. result.push(space);
  1225. result.push(this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT));
  1226. result.push(space + '}' + space);
  1227. } else {
  1228. // import {
  1229. // ...,
  1230. // ...,
  1231. // } from "...";
  1232. withIndent(function (indent) {
  1233. var i, iz;
  1234. result.push(newline);
  1235. for (i = cursor, iz = stmt.specifiers.length; i < iz; ++i) {
  1236. result.push(indent);
  1237. result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT));
  1238. if (i + 1 < iz) {
  1239. result.push(',' + newline);
  1240. }
  1241. }
  1242. });
  1243. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  1244. result.push(newline);
  1245. }
  1246. result.push(base + '}' + space);
  1247. }
  1248. }
  1249. }
  1250. result = join(result, [
  1251. 'from' + space,
  1252. // ModuleSpecifier
  1253. this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
  1254. this.semicolon(flags)
  1255. ]);
  1256. return result;
  1257. },
  1258. VariableDeclarator: function (stmt, flags) {
  1259. var itemFlags = (flags & F_ALLOW_IN) ? E_TTT : E_FTT;
  1260. if (stmt.init) {
  1261. return [
  1262. this.generateExpression(stmt.id, Precedence.Assignment, itemFlags),
  1263. space,
  1264. '=',
  1265. space,
  1266. this.generateExpression(stmt.init, Precedence.Assignment, itemFlags)
  1267. ];
  1268. }
  1269. return this.generatePattern(stmt.id, Precedence.Assignment, itemFlags);
  1270. },
  1271. VariableDeclaration: function (stmt, flags) {
  1272. // VariableDeclarator is typed as Statement,
  1273. // but joined with comma (not LineTerminator).
  1274. // So if comment is attached to target node, we should specialize.
  1275. var result, i, iz, node, bodyFlags, that = this;
  1276. result = [ stmt.kind ];
  1277. bodyFlags = (flags & F_ALLOW_IN) ? S_TFFF : S_FFFF;
  1278. function block() {
  1279. node = stmt.declarations[0];
  1280. if (extra.comment && node.leadingComments) {
  1281. result.push('\n');
  1282. result.push(addIndent(that.generateStatement(node, bodyFlags)));
  1283. } else {
  1284. result.push(noEmptySpace());
  1285. result.push(that.generateStatement(node, bodyFlags));
  1286. }
  1287. for (i = 1, iz = stmt.declarations.length; i < iz; ++i) {
  1288. node = stmt.declarations[i];
  1289. if (extra.comment && node.leadingComments) {
  1290. result.push(',' + newline);
  1291. result.push(addIndent(that.generateStatement(node, bodyFlags)));
  1292. } else {
  1293. result.push(',' + space);
  1294. result.push(that.generateStatement(node, bodyFlags));
  1295. }
  1296. }
  1297. }
  1298. if (stmt.declarations.length > 1) {
  1299. withIndent(block);
  1300. } else {
  1301. block();
  1302. }
  1303. result.push(this.semicolon(flags));
  1304. return result;
  1305. },
  1306. StaticBlock: function (stmt, flags) {
  1307. return [
  1308. 'static' + space,
  1309. this.BlockStatement(stmt, flags)
  1310. ];
  1311. },
  1312. ThrowStatement: function (stmt, flags) {
  1313. return [join(
  1314. 'throw',
  1315. this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
  1316. ), this.semicolon(flags)];
  1317. },
  1318. TryStatement: function (stmt, flags) {
  1319. var result, i, iz, guardedHandlers;
  1320. result = ['try', this.maybeBlock(stmt.block, S_TFFF)];
  1321. result = this.maybeBlockSuffix(stmt.block, result);
  1322. if (stmt.handlers) {
  1323. // old interface
  1324. for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
  1325. result = join(result, this.generateStatement(stmt.handlers[i], S_TFFF));
  1326. if (stmt.finalizer || i + 1 !== iz) {
  1327. result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
  1328. }
  1329. }
  1330. } else {
  1331. guardedHandlers = stmt.guardedHandlers || [];
  1332. for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
  1333. result = join(result, this.generateStatement(guardedHandlers[i], S_TFFF));
  1334. if (stmt.finalizer || i + 1 !== iz) {
  1335. result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
  1336. }
  1337. }
  1338. // new interface
  1339. if (stmt.handler) {
  1340. if (Array.isArray(stmt.handler)) {
  1341. for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
  1342. result = join(result, this.generateStatement(stmt.handler[i], S_TFFF));
  1343. if (stmt.finalizer || i + 1 !== iz) {
  1344. result = this.maybeBlockSuffix(stmt.handler[i].body, result);
  1345. }
  1346. }
  1347. } else {
  1348. result = join(result, this.generateStatement(stmt.handler, S_TFFF));
  1349. if (stmt.finalizer) {
  1350. result = this.maybeBlockSuffix(stmt.handler.body, result);
  1351. }
  1352. }
  1353. }
  1354. }
  1355. if (stmt.finalizer) {
  1356. result = join(result, ['finally', this.maybeBlock(stmt.finalizer, S_TFFF)]);
  1357. }
  1358. return result;
  1359. },
  1360. SwitchStatement: function (stmt, flags) {
  1361. var result, fragment, i, iz, bodyFlags, that = this;
  1362. withIndent(function () {
  1363. result = [
  1364. 'switch' + space + '(',
  1365. that.generateExpression(stmt.discriminant, Precedence.Sequence, E_TTT),
  1366. ')' + space + '{' + newline
  1367. ];
  1368. });
  1369. if (stmt.cases) {
  1370. bodyFlags = S_TFFF;
  1371. for (i = 0, iz = stmt.cases.length; i < iz; ++i) {
  1372. if (i === iz - 1) {
  1373. bodyFlags |= F_SEMICOLON_OPT;
  1374. }
  1375. fragment = addIndent(this.generateStatement(stmt.cases[i], bodyFlags));
  1376. result.push(fragment);
  1377. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  1378. result.push(newline);
  1379. }
  1380. }
  1381. }
  1382. result.push(addIndent('}'));
  1383. return result;
  1384. },
  1385. SwitchCase: function (stmt, flags) {
  1386. var result, fragment, i, iz, bodyFlags, that = this;
  1387. withIndent(function () {
  1388. if (stmt.test) {
  1389. result = [
  1390. join('case', that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
  1391. ':'
  1392. ];
  1393. } else {
  1394. result = ['default:'];
  1395. }
  1396. i = 0;
  1397. iz = stmt.consequent.length;
  1398. if (iz && stmt.consequent[0].type === Syntax.BlockStatement) {
  1399. fragment = that.maybeBlock(stmt.consequent[0], S_TFFF);
  1400. result.push(fragment);
  1401. i = 1;
  1402. }
  1403. if (i !== iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  1404. result.push(newline);
  1405. }
  1406. bodyFlags = S_TFFF;
  1407. for (; i < iz; ++i) {
  1408. if (i === iz - 1 && flags & F_SEMICOLON_OPT) {
  1409. bodyFlags |= F_SEMICOLON_OPT;
  1410. }
  1411. fragment = addIndent(that.generateStatement(stmt.consequent[i], bodyFlags));
  1412. result.push(fragment);
  1413. if (i + 1 !== iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  1414. result.push(newline);
  1415. }
  1416. }
  1417. });
  1418. return result;
  1419. },
  1420. IfStatement: function (stmt, flags) {
  1421. var result, bodyFlags, semicolonOptional, that = this;
  1422. withIndent(function () {
  1423. result = [
  1424. 'if' + space + '(',
  1425. that.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
  1426. ')'
  1427. ];
  1428. });
  1429. semicolonOptional = flags & F_SEMICOLON_OPT;
  1430. bodyFlags = S_TFFF;
  1431. if (semicolonOptional) {
  1432. bodyFlags |= F_SEMICOLON_OPT;
  1433. }
  1434. if (stmt.alternate) {
  1435. result.push(this.maybeBlock(stmt.consequent, S_TFFF));
  1436. result = this.maybeBlockSuffix(stmt.consequent, result);
  1437. if (stmt.alternate.type === Syntax.IfStatement) {
  1438. result = join(result, ['else ', this.generateStatement(stmt.alternate, bodyFlags)]);
  1439. } else {
  1440. result = join(result, join('else', this.maybeBlock(stmt.alternate, bodyFlags)));
  1441. }
  1442. } else {
  1443. result.push(this.maybeBlock(stmt.consequent, bodyFlags));
  1444. }
  1445. return result;
  1446. },
  1447. ForStatement: function (stmt, flags) {
  1448. var result, that = this;
  1449. withIndent(function () {
  1450. result = ['for' + space + '('];
  1451. if (stmt.init) {
  1452. if (stmt.init.type === Syntax.VariableDeclaration) {
  1453. result.push(that.generateStatement(stmt.init, S_FFFF));
  1454. } else {
  1455. // F_ALLOW_IN becomes false.
  1456. result.push(that.generateExpression(stmt.init, Precedence.Sequence, E_FTT));
  1457. result.push(';');
  1458. }
  1459. } else {
  1460. result.push(';');
  1461. }
  1462. if (stmt.test) {
  1463. result.push(space);
  1464. result.push(that.generateExpression(stmt.test, Precedence.Sequence, E_TTT));
  1465. result.push(';');
  1466. } else {
  1467. result.push(';');
  1468. }
  1469. if (stmt.update) {
  1470. result.push(space);
  1471. result.push(that.generateExpression(stmt.update, Precedence.Sequence, E_TTT));
  1472. result.push(')');
  1473. } else {
  1474. result.push(')');
  1475. }
  1476. });
  1477. result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
  1478. return result;
  1479. },
  1480. ForInStatement: function (stmt, flags) {
  1481. return this.generateIterationForStatement('in', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF);
  1482. },
  1483. ForOfStatement: function (stmt, flags) {
  1484. return this.generateIterationForStatement('of', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF);
  1485. },
  1486. LabeledStatement: function (stmt, flags) {
  1487. return [stmt.label.name + ':', this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)];
  1488. },
  1489. Program: function (stmt, flags) {
  1490. var result, fragment, i, iz, bodyFlags;
  1491. iz = stmt.body.length;
  1492. result = [safeConcatenation && iz > 0 ? '\n' : ''];
  1493. bodyFlags = S_TFTF;
  1494. for (i = 0; i < iz; ++i) {
  1495. if (!safeConcatenation && i === iz - 1) {
  1496. bodyFlags |= F_SEMICOLON_OPT;
  1497. }
  1498. if (preserveBlankLines) {
  1499. // handle spaces before the first line
  1500. if (i === 0) {
  1501. if (!stmt.body[0].leadingComments) {
  1502. generateBlankLines(stmt.range[0], stmt.body[i].range[0], result);
  1503. }
  1504. }
  1505. // handle spaces between lines
  1506. if (i > 0) {
  1507. if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
  1508. generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
  1509. }
  1510. }
  1511. }
  1512. fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags));
  1513. result.push(fragment);
  1514. if (i + 1 < iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  1515. if (preserveBlankLines) {
  1516. if (!stmt.body[i + 1].leadingComments) {
  1517. result.push(newline);
  1518. }
  1519. } else {
  1520. result.push(newline);
  1521. }
  1522. }
  1523. if (preserveBlankLines) {
  1524. // handle spaces after the last line
  1525. if (i === iz - 1) {
  1526. if (!stmt.body[i].trailingComments) {
  1527. generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
  1528. }
  1529. }
  1530. }
  1531. }
  1532. return result;
  1533. },
  1534. FunctionDeclaration: function (stmt, flags) {
  1535. return [
  1536. generateAsyncPrefix(stmt, true),
  1537. 'function',
  1538. generateStarSuffix(stmt) || noEmptySpace(),
  1539. stmt.id ? generateIdentifier(stmt.id) : '',
  1540. this.generateFunctionBody(stmt)
  1541. ];
  1542. },
  1543. ReturnStatement: function (stmt, flags) {
  1544. if (stmt.argument) {
  1545. return [join(
  1546. 'return',
  1547. this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
  1548. ), this.semicolon(flags)];
  1549. }
  1550. return ['return' + this.semicolon(flags)];
  1551. },
  1552. WhileStatement: function (stmt, flags) {
  1553. var result, that = this;
  1554. withIndent(function () {
  1555. result = [
  1556. 'while' + space + '(',
  1557. that.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
  1558. ')'
  1559. ];
  1560. });
  1561. result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
  1562. return result;
  1563. },
  1564. WithStatement: function (stmt, flags) {
  1565. var result, that = this;
  1566. withIndent(function () {
  1567. result = [
  1568. 'with' + space + '(',
  1569. that.generateExpression(stmt.object, Precedence.Sequence, E_TTT),
  1570. ')'
  1571. ];
  1572. });
  1573. result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
  1574. return result;
  1575. }
  1576. };
  1577. merge(CodeGenerator.prototype, CodeGenerator.Statement);
  1578. // Expressions.
  1579. CodeGenerator.Expression = {
  1580. SequenceExpression: function (expr, precedence, flags) {
  1581. var result, i, iz;
  1582. if (Precedence.Sequence < precedence) {
  1583. flags |= F_ALLOW_IN;
  1584. }
  1585. result = [];
  1586. for (i = 0, iz = expr.expressions.length; i < iz; ++i) {
  1587. result.push(this.generateExpression(expr.expressions[i], Precedence.Assignment, flags));
  1588. if (i + 1 < iz) {
  1589. result.push(',' + space);
  1590. }
  1591. }
  1592. return parenthesize(result, Precedence.Sequence, precedence);
  1593. },
  1594. AssignmentExpression: function (expr, precedence, flags) {
  1595. return this.generateAssignment(expr.left, expr.right, expr.operator, precedence, flags);
  1596. },
  1597. ArrowFunctionExpression: function (expr, precedence, flags) {
  1598. return parenthesize(this.generateFunctionBody(expr), Precedence.ArrowFunction, precedence);
  1599. },
  1600. ConditionalExpression: function (expr, precedence, flags) {
  1601. if (Precedence.Conditional < precedence) {
  1602. flags |= F_ALLOW_IN;
  1603. }
  1604. return parenthesize(
  1605. [
  1606. this.generateExpression(expr.test, Precedence.LogicalOR, flags),
  1607. space + '?' + space,
  1608. this.generateExpression(expr.consequent, Precedence.Assignment, flags),
  1609. space + ':' + space,
  1610. this.generateExpression(expr.alternate, Precedence.Assignment, flags)
  1611. ],
  1612. Precedence.Conditional,
  1613. precedence
  1614. );
  1615. },
  1616. LogicalExpression: function (expr, precedence, flags) {
  1617. return this.BinaryExpression(expr, precedence, flags);
  1618. },
  1619. BinaryExpression: function (expr, precedence, flags) {
  1620. var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource;
  1621. currentPrecedence = BinaryPrecedence[expr.operator];
  1622. leftPrecedence = currentPrecedence;
  1623. rightPrecedence = currentPrecedence + 1;
  1624. switch (expr.operator) {
  1625. case '**':
  1626. leftPrecedence = Precedence.Postfix;
  1627. rightPrecedence = currentPrecedence;
  1628. break;
  1629. case '??':
  1630. if (expr.left.type === Syntax.LogicalExpression && (expr.left.operator === '||' || expr.left.operator === '&&')) {
  1631. leftPrecedence = BinaryPrecedence[expr.left.operator] + 1;
  1632. }
  1633. if (expr.right.type === Syntax.LogicalExpression && expr.right.operator === '&&') {
  1634. rightPrecedence = BinaryPrecedence[expr.right.operator] + 1;
  1635. }
  1636. break;
  1637. case '||':
  1638. if (expr.left.type === Syntax.LogicalExpression && expr.left.operator === '??') {
  1639. leftPrecedence = BinaryPrecedence[expr.left.operator] + 1;
  1640. }
  1641. break;
  1642. }
  1643. if (currentPrecedence < precedence) {
  1644. flags |= F_ALLOW_IN;
  1645. }
  1646. fragment = this.generateExpression(expr.left, leftPrecedence, flags);
  1647. leftSource = fragment.toString();
  1648. if (leftSource.charCodeAt(leftSource.length - 1) === 0x2F /* / */ && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
  1649. result = [fragment, noEmptySpace(), expr.operator];
  1650. } else {
  1651. result = join(fragment, expr.operator);
  1652. }
  1653. fragment = this.generateExpression(expr.right, rightPrecedence, flags);
  1654. if (expr.operator === '/' && fragment.toString().charAt(0) === '/' ||
  1655. expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') {
  1656. // If '/' concats with '/' or `<` concats with `!--`, it is interpreted as comment start
  1657. result.push(noEmptySpace());
  1658. result.push(fragment);
  1659. } else {
  1660. result = join(result, fragment);
  1661. }
  1662. if (expr.operator === 'in' && !(flags & F_ALLOW_IN)) {
  1663. return ['(', result, ')'];
  1664. }
  1665. return parenthesize(result, currentPrecedence, precedence);
  1666. },
  1667. CallExpression: function (expr, precedence, flags) {
  1668. var result, i, iz, isIIFE;
  1669. // F_ALLOW_UNPARATH_NEW becomes false.
  1670. result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)];
  1671. if (expr.optional) {
  1672. result.push('?.');
  1673. }
  1674. result.push('(');
  1675. for (i = 0, iz = expr['arguments'].length; i < iz; ++i) {
  1676. result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
  1677. if (i + 1 < iz) {
  1678. result.push(',' + space);
  1679. }
  1680. }
  1681. result.push(')');
  1682. if (!(flags & F_ALLOW_CALL)) {
  1683. return ['(', result, ')'];
  1684. }
  1685. isIIFE = expr.callee.id === null && expr.callee.params.length === 0;
  1686. return isIIFE
  1687. ? parenthesize(result, precedence, Precedence.Call)
  1688. : parenthesize(result, Precedence.Call, precedence);
  1689. },
  1690. ChainExpression: function (expr, precedence, flags) {
  1691. if (Precedence.OptionalChaining < precedence) {
  1692. flags |= F_ALLOW_CALL;
  1693. }
  1694. var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags);
  1695. return parenthesize(result, Precedence.OptionalChaining, precedence);
  1696. },
  1697. NewExpression: function (expr, precedence, flags) {
  1698. var result, length, i, iz, itemFlags;
  1699. length = expr['arguments'].length;
  1700. // F_ALLOW_CALL becomes false.
  1701. // F_ALLOW_UNPARATH_NEW may become false.
  1702. itemFlags = (flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0) ? E_TFT : E_TFF;
  1703. result = join(
  1704. 'new',
  1705. this.generateExpression(expr.callee, Precedence.New, itemFlags)
  1706. );
  1707. if (!(flags & F_ALLOW_UNPARATH_NEW) || parentheses || length > 0) {
  1708. result.push('(');
  1709. for (i = 0, iz = length; i < iz; ++i) {
  1710. result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
  1711. if (i + 1 < iz) {
  1712. result.push(',' + space);
  1713. }
  1714. }
  1715. result.push(')');
  1716. }
  1717. return parenthesize(result, Precedence.New, precedence);
  1718. },
  1719. MemberExpression: function (expr, precedence, flags) {
  1720. var result, fragment;
  1721. // F_ALLOW_UNPARATH_NEW becomes false.
  1722. result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)];
  1723. if (expr.computed) {
  1724. if (expr.optional) {
  1725. result.push('?.');
  1726. }
  1727. result.push('[');
  1728. result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT));
  1729. result.push(']');
  1730. } else {
  1731. if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
  1732. fragment = toSourceNodeWhenNeeded(result).toString();
  1733. // When the following conditions are all true,
  1734. // 1. No floating point
  1735. // 2. Don't have exponents
  1736. // 3. The last character is a decimal digit
  1737. // 4. Not hexadecimal OR octal number literal
  1738. // we should add a floating point.
  1739. if (
  1740. fragment.indexOf('.') < 0 &&
  1741. !/[eExX]/.test(fragment) &&
  1742. esutils.code.isDecimalDigit(fragment.charCodeAt(fragment.length - 1)) &&
  1743. !(fragment.length >= 2 && fragment.charCodeAt(0) === 48) // '0'
  1744. ) {
  1745. result.push(' ');
  1746. }
  1747. }
  1748. result.push(expr.optional ? '?.' : '.');
  1749. result.push(generateIdentifier(expr.property));
  1750. }
  1751. return parenthesize(result, Precedence.Member, precedence);
  1752. },
  1753. MetaProperty: function (expr, precedence, flags) {
  1754. var result;
  1755. result = [];
  1756. result.push(typeof expr.meta === "string" ? expr.meta : generateIdentifier(expr.meta));
  1757. result.push('.');
  1758. result.push(typeof expr.property === "string" ? expr.property : generateIdentifier(expr.property));
  1759. return parenthesize(result, Precedence.Member, precedence);
  1760. },
  1761. UnaryExpression: function (expr, precedence, flags) {
  1762. var result, fragment, rightCharCode, leftSource, leftCharCode;
  1763. fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
  1764. if (space === '') {
  1765. result = join(expr.operator, fragment);
  1766. } else {
  1767. result = [expr.operator];
  1768. if (expr.operator.length > 2) {
  1769. // delete, void, typeof
  1770. // get `typeof []`, not `typeof[]`
  1771. result = join(result, fragment);
  1772. } else {
  1773. // Prevent inserting spaces between operator and argument if it is unnecessary
  1774. // like, `!cond`
  1775. leftSource = toSourceNodeWhenNeeded(result).toString();
  1776. leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
  1777. rightCharCode = fragment.toString().charCodeAt(0);
  1778. if (((leftCharCode === 0x2B /* + */ || leftCharCode === 0x2D /* - */) && leftCharCode === rightCharCode) ||
  1779. (esutils.code.isIdentifierPartES5(leftCharCode) && esutils.code.isIdentifierPartES5(rightCharCode))) {
  1780. result.push(noEmptySpace());
  1781. result.push(fragment);
  1782. } else {
  1783. result.push(fragment);
  1784. }
  1785. }
  1786. }
  1787. return parenthesize(result, Precedence.Unary, precedence);
  1788. },
  1789. YieldExpression: function (expr, precedence, flags) {
  1790. var result;
  1791. if (expr.delegate) {
  1792. result = 'yield*';
  1793. } else {
  1794. result = 'yield';
  1795. }
  1796. if (expr.argument) {
  1797. result = join(
  1798. result,
  1799. this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
  1800. );
  1801. }
  1802. return parenthesize(result, Precedence.Yield, precedence);
  1803. },
  1804. AwaitExpression: function (expr, precedence, flags) {
  1805. var result = join(
  1806. expr.all ? 'await*' : 'await',
  1807. this.generateExpression(expr.argument, Precedence.Await, E_TTT)
  1808. );
  1809. return parenthesize(result, Precedence.Await, precedence);
  1810. },
  1811. UpdateExpression: function (expr, precedence, flags) {
  1812. if (expr.prefix) {
  1813. return parenthesize(
  1814. [
  1815. expr.operator,
  1816. this.generateExpression(expr.argument, Precedence.Unary, E_TTT)
  1817. ],
  1818. Precedence.Unary,
  1819. precedence
  1820. );
  1821. }
  1822. return parenthesize(
  1823. [
  1824. this.generateExpression(expr.argument, Precedence.Postfix, E_TTT),
  1825. expr.operator
  1826. ],
  1827. Precedence.Postfix,
  1828. precedence
  1829. );
  1830. },
  1831. FunctionExpression: function (expr, precedence, flags) {
  1832. var result = [
  1833. generateAsyncPrefix(expr, true),
  1834. 'function'
  1835. ];
  1836. if (expr.id) {
  1837. result.push(generateStarSuffix(expr) || noEmptySpace());
  1838. result.push(generateIdentifier(expr.id));
  1839. } else {
  1840. result.push(generateStarSuffix(expr) || space);
  1841. }
  1842. result.push(this.generateFunctionBody(expr));
  1843. return result;
  1844. },
  1845. ArrayPattern: function (expr, precedence, flags) {
  1846. return this.ArrayExpression(expr, precedence, flags, true);
  1847. },
  1848. ArrayExpression: function (expr, precedence, flags, isPattern) {
  1849. var result, multiline, that = this;
  1850. if (!expr.elements.length) {
  1851. return '[]';
  1852. }
  1853. multiline = isPattern ? false : expr.elements.length > 1;
  1854. result = ['[', multiline ? newline : ''];
  1855. withIndent(function (indent) {
  1856. var i, iz;
  1857. for (i = 0, iz = expr.elements.length; i < iz; ++i) {
  1858. if (!expr.elements[i]) {
  1859. if (multiline) {
  1860. result.push(indent);
  1861. }
  1862. if (i + 1 === iz) {
  1863. result.push(',');
  1864. }
  1865. } else {
  1866. result.push(multiline ? indent : '');
  1867. result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT));
  1868. }
  1869. if (i + 1 < iz) {
  1870. result.push(',' + (multiline ? newline : space));
  1871. }
  1872. }
  1873. });
  1874. if (multiline && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  1875. result.push(newline);
  1876. }
  1877. result.push(multiline ? base : '');
  1878. result.push(']');
  1879. return result;
  1880. },
  1881. RestElement: function(expr, precedence, flags) {
  1882. return '...' + this.generatePattern(expr.argument);
  1883. },
  1884. ClassExpression: function (expr, precedence, flags) {
  1885. var result, fragment;
  1886. result = ['class'];
  1887. if (expr.id) {
  1888. result = join(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
  1889. }
  1890. if (expr.superClass) {
  1891. fragment = join('extends', this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
  1892. result = join(result, fragment);
  1893. }
  1894. result.push(space);
  1895. result.push(this.generateStatement(expr.body, S_TFFT));
  1896. return result;
  1897. },
  1898. MethodDefinition: function (expr, precedence, flags) {
  1899. var result, fragment;
  1900. if (expr['static']) {
  1901. result = ['static' + space];
  1902. } else {
  1903. result = [];
  1904. }
  1905. if (expr.kind === 'get' || expr.kind === 'set') {
  1906. fragment = [
  1907. join(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
  1908. this.generateFunctionBody(expr.value)
  1909. ];
  1910. } else {
  1911. fragment = [
  1912. generateMethodPrefix(expr),
  1913. this.generatePropertyKey(expr.key, expr.computed),
  1914. this.generateFunctionBody(expr.value)
  1915. ];
  1916. }
  1917. return join(result, fragment);
  1918. },
  1919. PrivateIdentifier: function (expr, precedence, flags) {
  1920. return generateIdentifier(expr);
  1921. },
  1922. Property: function (expr, precedence, flags) {
  1923. if (expr.kind === 'get' || expr.kind === 'set') {
  1924. return [
  1925. expr.kind, noEmptySpace(),
  1926. this.generatePropertyKey(expr.key, expr.computed),
  1927. this.generateFunctionBody(expr.value)
  1928. ];
  1929. }
  1930. if (expr.shorthand) {
  1931. if (expr.value.type === "AssignmentPattern") {
  1932. return this.AssignmentPattern(expr.value, Precedence.Sequence, E_TTT);
  1933. }
  1934. return this.generatePropertyKey(expr.key, expr.computed);
  1935. }
  1936. if (expr.method) {
  1937. return [
  1938. generateMethodPrefix(expr),
  1939. this.generatePropertyKey(expr.key, expr.computed),
  1940. this.generateFunctionBody(expr.value)
  1941. ];
  1942. }
  1943. return [
  1944. this.generatePropertyKey(expr.key, expr.computed),
  1945. ':' + space,
  1946. this.generateExpression(expr.value, Precedence.Assignment, E_TTT)
  1947. ];
  1948. },
  1949. PropertyDefinition: function (expr, precedence, flags) {
  1950. var result;
  1951. if (expr.static) {
  1952. result = ['static '];
  1953. } else {
  1954. result = [];
  1955. }
  1956. result.push(this.generatePropertyKey(expr.key, expr.computed));
  1957. if (expr.value) {
  1958. result.push( space + '=' + space);
  1959. result.push(this.generateExpression(expr.value, Precedence.Assignment, E_TTT));
  1960. }
  1961. result.push(this.semicolon(flags));
  1962. return result;
  1963. },
  1964. ObjectExpression: function (expr, precedence, flags) {
  1965. var multiline, result, fragment, that = this;
  1966. if (!expr.properties.length) {
  1967. return '{}';
  1968. }
  1969. multiline = expr.properties.length > 1;
  1970. withIndent(function () {
  1971. fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT);
  1972. });
  1973. if (!multiline) {
  1974. // issues 4
  1975. // Do not transform from
  1976. // dejavu.Class.declare({
  1977. // method2: function () {}
  1978. // });
  1979. // to
  1980. // dejavu.Class.declare({method2: function () {
  1981. // }});
  1982. if (!hasLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
  1983. return [ '{', space, fragment, space, '}' ];
  1984. }
  1985. }
  1986. withIndent(function (indent) {
  1987. var i, iz;
  1988. result = [ '{', newline, indent, fragment ];
  1989. if (multiline) {
  1990. result.push(',' + newline);
  1991. for (i = 1, iz = expr.properties.length; i < iz; ++i) {
  1992. result.push(indent);
  1993. result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT));
  1994. if (i + 1 < iz) {
  1995. result.push(',' + newline);
  1996. }
  1997. }
  1998. }
  1999. });
  2000. if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  2001. result.push(newline);
  2002. }
  2003. result.push(base);
  2004. result.push('}');
  2005. return result;
  2006. },
  2007. AssignmentPattern: function(expr, precedence, flags) {
  2008. return this.generateAssignment(expr.left, expr.right, '=', precedence, flags);
  2009. },
  2010. ObjectPattern: function (expr, precedence, flags) {
  2011. var result, i, iz, multiline, property, that = this;
  2012. if (!expr.properties.length) {
  2013. return '{}';
  2014. }
  2015. multiline = false;
  2016. if (expr.properties.length === 1) {
  2017. property = expr.properties[0];
  2018. if (
  2019. property.type === Syntax.Property
  2020. && property.value.type !== Syntax.Identifier
  2021. ) {
  2022. multiline = true;
  2023. }
  2024. } else {
  2025. for (i = 0, iz = expr.properties.length; i < iz; ++i) {
  2026. property = expr.properties[i];
  2027. if (
  2028. property.type === Syntax.Property
  2029. && !property.shorthand
  2030. ) {
  2031. multiline = true;
  2032. break;
  2033. }
  2034. }
  2035. }
  2036. result = ['{', multiline ? newline : '' ];
  2037. withIndent(function (indent) {
  2038. var i, iz;
  2039. for (i = 0, iz = expr.properties.length; i < iz; ++i) {
  2040. result.push(multiline ? indent : '');
  2041. result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT));
  2042. if (i + 1 < iz) {
  2043. result.push(',' + (multiline ? newline : space));
  2044. }
  2045. }
  2046. });
  2047. if (multiline && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
  2048. result.push(newline);
  2049. }
  2050. result.push(multiline ? base : '');
  2051. result.push('}');
  2052. return result;
  2053. },
  2054. ThisExpression: function (expr, precedence, flags) {
  2055. return 'this';
  2056. },
  2057. Super: function (expr, precedence, flags) {
  2058. return 'super';
  2059. },
  2060. Identifier: function (expr, precedence, flags) {
  2061. return generateIdentifier(expr);
  2062. },
  2063. ImportDefaultSpecifier: function (expr, precedence, flags) {
  2064. return generateIdentifier(expr.id || expr.local);
  2065. },
  2066. ImportNamespaceSpecifier: function (expr, precedence, flags) {
  2067. var result = ['*'];
  2068. var id = expr.id || expr.local;
  2069. if (id) {
  2070. result.push(space + 'as' + noEmptySpace() + generateIdentifier(id));
  2071. }
  2072. return result;
  2073. },
  2074. ImportSpecifier: function (expr, precedence, flags) {
  2075. var imported = expr.imported;
  2076. var result = [ imported.name ];
  2077. var local = expr.local;
  2078. if (local && local.name !== imported.name) {
  2079. result.push(noEmptySpace() + 'as' + noEmptySpace() + generateIdentifier(local));
  2080. }
  2081. return result;
  2082. },
  2083. ExportSpecifier: function (expr, precedence, flags) {
  2084. var local = expr.local;
  2085. var result = [ local.name ];
  2086. var exported = expr.exported;
  2087. if (exported && exported.name !== local.name) {
  2088. result.push(noEmptySpace() + 'as' + noEmptySpace() + generateIdentifier(exported));
  2089. }
  2090. return result;
  2091. },
  2092. Literal: function (expr, precedence, flags) {
  2093. var raw;
  2094. if (expr.hasOwnProperty('raw') && parse && extra.raw) {
  2095. try {
  2096. raw = parse(expr.raw).body[0].expression;
  2097. if (raw.type === Syntax.Literal) {
  2098. if (raw.value === expr.value) {
  2099. return expr.raw;
  2100. }
  2101. }
  2102. } catch (e) {
  2103. // not use raw property
  2104. }
  2105. }
  2106. if (expr.regex) {
  2107. return '/' + expr.regex.pattern + '/' + expr.regex.flags;
  2108. }
  2109. // BigInt, eg: 1n
  2110. if (typeof expr.bigint === 'string' && expr.raw) {
  2111. return expr.raw;
  2112. }
  2113. if (expr.value === null) {
  2114. return 'null';
  2115. }
  2116. if (typeof expr.value === 'string') {
  2117. return escapeString(expr.value);
  2118. }
  2119. if (typeof expr.value === 'number') {
  2120. // Has Numeric Separator
  2121. if (expr.raw && expr.raw.indexOf('_') !== -1) {
  2122. return expr.raw;
  2123. }
  2124. return generateNumber(expr.value);
  2125. }
  2126. if (typeof expr.value === 'boolean') {
  2127. return expr.value ? 'true' : 'false';
  2128. }
  2129. return generateRegExp(expr.value);
  2130. },
  2131. GeneratorExpression: function (expr, precedence, flags) {
  2132. return this.ComprehensionExpression(expr, precedence, flags);
  2133. },
  2134. ComprehensionExpression: function (expr, precedence, flags) {
  2135. // GeneratorExpression should be parenthesized with (...), ComprehensionExpression with [...]
  2136. // Due to https://bugzilla.mozilla.org/show_bug.cgi?id=883468 position of expr.body can differ in Spidermonkey and ES6
  2137. var result, i, iz, fragment, that = this;
  2138. result = (expr.type === Syntax.GeneratorExpression) ? ['('] : ['['];
  2139. if (extra.moz.comprehensionExpressionStartsWithAssignment) {
  2140. fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
  2141. result.push(fragment);
  2142. }
  2143. if (expr.blocks) {
  2144. withIndent(function () {
  2145. for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
  2146. fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
  2147. if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
  2148. result = join(result, fragment);
  2149. } else {
  2150. result.push(fragment);
  2151. }
  2152. }
  2153. });
  2154. }
  2155. if (expr.filter) {
  2156. result = join(result, 'if' + space);
  2157. fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
  2158. result = join(result, [ '(', fragment, ')' ]);
  2159. }
  2160. if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
  2161. fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
  2162. result = join(result, fragment);
  2163. }
  2164. result.push((expr.type === Syntax.GeneratorExpression) ? ')' : ']');
  2165. return result;
  2166. },
  2167. ComprehensionBlock: function (expr, precedence, flags) {
  2168. var fragment;
  2169. if (expr.left.type === Syntax.VariableDeclaration) {
  2170. fragment = [
  2171. expr.left.kind, noEmptySpace(),
  2172. this.generateStatement(expr.left.declarations[0], S_FFFF)
  2173. ];
  2174. } else {
  2175. fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
  2176. }
  2177. fragment = join(fragment, expr.of ? 'of' : 'in');
  2178. fragment = join(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
  2179. return [ 'for' + space + '(', fragment, ')' ];
  2180. },
  2181. SpreadElement: function (expr, precedence, flags) {
  2182. return [
  2183. '...',
  2184. this.generateExpression(expr.argument, Precedence.Assignment, E_TTT)
  2185. ];
  2186. },
  2187. TaggedTemplateExpression: function (expr, precedence, flags) {
  2188. var itemFlags = E_TTF;
  2189. if (!(flags & F_ALLOW_CALL)) {
  2190. itemFlags = E_TFF;
  2191. }
  2192. var result = [
  2193. this.generateExpression(expr.tag, Precedence.Call, itemFlags),
  2194. this.generateExpression(expr.quasi, Precedence.Primary, E_FFT)
  2195. ];
  2196. return parenthesize(result, Precedence.TaggedTemplate, precedence);
  2197. },
  2198. TemplateElement: function (expr, precedence, flags) {
  2199. // Don't use "cooked". Since tagged template can use raw template
  2200. // representation. So if we do so, it breaks the script semantics.
  2201. return expr.value.raw;
  2202. },
  2203. TemplateLiteral: function (expr, precedence, flags) {
  2204. var result, i, iz;
  2205. result = [ '`' ];
  2206. for (i = 0, iz = expr.quasis.length; i < iz; ++i) {
  2207. result.push(this.generateExpression(expr.quasis[i], Precedence.Primary, E_TTT));
  2208. if (i + 1 < iz) {
  2209. result.push('${' + space);
  2210. result.push(this.generateExpression(expr.expressions[i], Precedence.Sequence, E_TTT));
  2211. result.push(space + '}');
  2212. }
  2213. }
  2214. result.push('`');
  2215. return result;
  2216. },
  2217. ModuleSpecifier: function (expr, precedence, flags) {
  2218. return this.Literal(expr, precedence, flags);
  2219. },
  2220. ImportExpression: function(expr, precedence, flag) {
  2221. return parenthesize([
  2222. 'import(',
  2223. this.generateExpression(expr.source, Precedence.Assignment, E_TTT),
  2224. ')'
  2225. ], Precedence.Call, precedence);
  2226. }
  2227. };
  2228. merge(CodeGenerator.prototype, CodeGenerator.Expression);
  2229. CodeGenerator.prototype.generateExpression = function (expr, precedence, flags) {
  2230. var result, type;
  2231. type = expr.type || Syntax.Property;
  2232. if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) {
  2233. return generateVerbatim(expr, precedence);
  2234. }
  2235. result = this[type](expr, precedence, flags);
  2236. if (extra.comment) {
  2237. result = addComments(expr, result);
  2238. }
  2239. return toSourceNodeWhenNeeded(result, expr);
  2240. };
  2241. CodeGenerator.prototype.generateStatement = function (stmt, flags) {
  2242. var result,
  2243. fragment;
  2244. result = this[stmt.type](stmt, flags);
  2245. // Attach comments
  2246. if (extra.comment) {
  2247. result = addComments(stmt, result);
  2248. }
  2249. fragment = toSourceNodeWhenNeeded(result).toString();
  2250. if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') {
  2251. result = sourceMap ? toSourceNodeWhenNeeded(result).replaceRight(/\s+$/, '') : fragment.replace(/\s+$/, '');
  2252. }
  2253. return toSourceNodeWhenNeeded(result, stmt);
  2254. };
  2255. function generateInternal(node) {
  2256. var codegen;
  2257. codegen = new CodeGenerator();
  2258. if (isStatement(node)) {
  2259. return codegen.generateStatement(node, S_TFFF);
  2260. }
  2261. if (isExpression(node)) {
  2262. return codegen.generateExpression(node, Precedence.Sequence, E_TTT);
  2263. }
  2264. throw new Error('Unknown node type: ' + node.type);
  2265. }
  2266. function generate(node, options) {
  2267. var defaultOptions = getDefaultOptions(), result, pair;
  2268. if (options != null) {
  2269. // Obsolete options
  2270. //
  2271. // `options.indent`
  2272. // `options.base`
  2273. //
  2274. // Instead of them, we can use `option.format.indent`.
  2275. if (typeof options.indent === 'string') {
  2276. defaultOptions.format.indent.style = options.indent;
  2277. }
  2278. if (typeof options.base === 'number') {
  2279. defaultOptions.format.indent.base = options.base;
  2280. }
  2281. options = updateDeeply(defaultOptions, options);
  2282. indent = options.format.indent.style;
  2283. if (typeof options.base === 'string') {
  2284. base = options.base;
  2285. } else {
  2286. base = stringRepeat(indent, options.format.indent.base);
  2287. }
  2288. } else {
  2289. options = defaultOptions;
  2290. indent = options.format.indent.style;
  2291. base = stringRepeat(indent, options.format.indent.base);
  2292. }
  2293. json = options.format.json;
  2294. renumber = options.format.renumber;
  2295. hexadecimal = json ? false : options.format.hexadecimal;
  2296. quotes = json ? 'double' : options.format.quotes;
  2297. escapeless = options.format.escapeless;
  2298. newline = options.format.newline;
  2299. space = options.format.space;
  2300. if (options.format.compact) {
  2301. newline = space = indent = base = '';
  2302. }
  2303. parentheses = options.format.parentheses;
  2304. semicolons = options.format.semicolons;
  2305. safeConcatenation = options.format.safeConcatenation;
  2306. directive = options.directive;
  2307. parse = json ? null : options.parse;
  2308. sourceMap = options.sourceMap;
  2309. sourceCode = options.sourceCode;
  2310. preserveBlankLines = options.format.preserveBlankLines && sourceCode !== null;
  2311. extra = options;
  2312. if (sourceMap) {
  2313. if (!exports.browser) {
  2314. // We assume environment is node.js
  2315. // And prevent from including source-map by browserify
  2316. SourceNode = require('source-map').SourceNode;
  2317. } else {
  2318. SourceNode = global.sourceMap.SourceNode;
  2319. }
  2320. }
  2321. result = generateInternal(node);
  2322. if (!sourceMap) {
  2323. pair = {code: result.toString(), map: null};
  2324. return options.sourceMapWithCode ? pair : pair.code;
  2325. }
  2326. pair = result.toStringWithSourceMap({
  2327. file: options.file,
  2328. sourceRoot: options.sourceMapRoot
  2329. });
  2330. if (options.sourceContent) {
  2331. pair.map.setSourceContent(options.sourceMap,
  2332. options.sourceContent);
  2333. }
  2334. if (options.sourceMapWithCode) {
  2335. return pair;
  2336. }
  2337. return pair.map.toString();
  2338. }
  2339. FORMAT_MINIFY = {
  2340. indent: {
  2341. style: '',
  2342. base: 0
  2343. },
  2344. renumber: true,
  2345. hexadecimal: true,
  2346. quotes: 'auto',
  2347. escapeless: true,
  2348. compact: true,
  2349. parentheses: false,
  2350. semicolons: false
  2351. };
  2352. FORMAT_DEFAULTS = getDefaultOptions().format;
  2353. exports.version = require('./package.json').version;
  2354. exports.generate = generate;
  2355. exports.attachComments = estraverse.attachComments;
  2356. exports.Precedence = updateDeeply({}, Precedence);
  2357. exports.browser = false;
  2358. exports.FORMAT_MINIFY = FORMAT_MINIFY;
  2359. exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS;
  2360. }());
  2361. /* vim: set sw=4 ts=4 et tw=80 : */