A Twitch.tv viewer reward and games system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

22893 lines
756 KiB

  1. !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.jade=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. 'use strict';
  3. var nodes = require('./nodes');
  4. var filters = require('./filters');
  5. var doctypes = require('./doctypes');
  6. var selfClosing = require('./self-closing');
  7. var runtime = require('./runtime');
  8. var utils = require('./utils');
  9. var parseJSExpression = require('character-parser').parseMax;
  10. var isConstant = require('constantinople');
  11. var toConstant = require('constantinople').toConstant;
  12. /**
  13. * Initialize `Compiler` with the given `node`.
  14. *
  15. * @param {Node} node
  16. * @param {Object} options
  17. * @api public
  18. */
  19. var Compiler = module.exports = function Compiler(node, options) {
  20. this.options = options = options || {};
  21. this.node = node;
  22. this.hasCompiledDoctype = false;
  23. this.hasCompiledTag = false;
  24. this.pp = options.pretty || false;
  25. this.debug = false !== options.compileDebug;
  26. this.indents = 0;
  27. this.parentIndents = 0;
  28. this.terse = false;
  29. if (options.doctype) this.setDoctype(options.doctype);
  30. };
  31. /**
  32. * Compiler prototype.
  33. */
  34. Compiler.prototype = {
  35. /**
  36. * Compile parse tree to JavaScript.
  37. *
  38. * @api public
  39. */
  40. compile: function(){
  41. this.buf = [];
  42. if (this.pp) this.buf.push("jade.indent = [];");
  43. this.lastBufferedIdx = -1;
  44. this.visit(this.node);
  45. return this.buf.join('\n');
  46. },
  47. /**
  48. * Sets the default doctype `name`. Sets terse mode to `true` when
  49. * html 5 is used, causing self-closing tags to end with ">" vs "/>",
  50. * and boolean attributes are not mirrored.
  51. *
  52. * @param {string} name
  53. * @api public
  54. */
  55. setDoctype: function(name){
  56. name = name || 'default';
  57. this.doctype = doctypes[name.toLowerCase()] || '<!DOCTYPE ' + name + '>';
  58. this.terse = this.doctype.toLowerCase() == '<!doctype html>';
  59. this.xml = 0 == this.doctype.indexOf('<?xml');
  60. },
  61. /**
  62. * Buffer the given `str` exactly as is or with interpolation
  63. *
  64. * @param {String} str
  65. * @param {Boolean} interpolate
  66. * @api public
  67. */
  68. buffer: function (str, interpolate) {
  69. var self = this;
  70. if (interpolate) {
  71. var match = /(\\)?([#!]){((?:.|\n)*)$/.exec(str);
  72. if (match) {
  73. this.buffer(str.substr(0, match.index), false);
  74. if (match[1]) { // escape
  75. this.buffer(match[2] + '{', false);
  76. this.buffer(match[3], true);
  77. return;
  78. } else {
  79. try {
  80. var rest = match[3];
  81. var range = parseJSExpression(rest);
  82. var code = ('!' == match[2] ? '' : 'jade.escape') + "((jade.interp = " + range.src + ") == null ? '' : jade.interp)";
  83. } catch (ex) {
  84. throw ex;
  85. //didn't match, just as if escaped
  86. this.buffer(match[2] + '{', false);
  87. this.buffer(match[3], true);
  88. return;
  89. }
  90. this.bufferExpression(code);
  91. this.buffer(rest.substr(range.end + 1), true);
  92. return;
  93. }
  94. }
  95. }
  96. str = JSON.stringify(str);
  97. str = str.substr(1, str.length - 2);
  98. if (this.lastBufferedIdx == this.buf.length) {
  99. if (this.lastBufferedType === 'code') this.lastBuffered += ' + "';
  100. this.lastBufferedType = 'text';
  101. this.lastBuffered += str;
  102. this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + '");'
  103. } else {
  104. this.buf.push('buf.push("' + str + '");');
  105. this.lastBufferedType = 'text';
  106. this.bufferStartChar = '"';
  107. this.lastBuffered = str;
  108. this.lastBufferedIdx = this.buf.length;
  109. }
  110. },
  111. /**
  112. * Buffer the given `src` so it is evaluated at run time
  113. *
  114. * @param {String} src
  115. * @api public
  116. */
  117. bufferExpression: function (src) {
  118. var fn = Function('', 'return (' + src + ');');
  119. if (isConstant(src)) {
  120. return this.buffer(fn(), false)
  121. }
  122. if (this.lastBufferedIdx == this.buf.length) {
  123. if (this.lastBufferedType === 'text') this.lastBuffered += '"';
  124. this.lastBufferedType = 'code';
  125. this.lastBuffered += ' + (' + src + ')';
  126. this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + ');'
  127. } else {
  128. this.buf.push('buf.push(' + src + ');');
  129. this.lastBufferedType = 'code';
  130. this.bufferStartChar = '';
  131. this.lastBuffered = '(' + src + ')';
  132. this.lastBufferedIdx = this.buf.length;
  133. }
  134. },
  135. /**
  136. * Buffer an indent based on the current `indent`
  137. * property and an additional `offset`.
  138. *
  139. * @param {Number} offset
  140. * @param {Boolean} newline
  141. * @api public
  142. */
  143. prettyIndent: function(offset, newline){
  144. offset = offset || 0;
  145. newline = newline ? '\n' : '';
  146. this.buffer(newline + Array(this.indents + offset).join(' '));
  147. if (this.parentIndents)
  148. this.buf.push("buf.push.apply(buf, jade.indent);");
  149. },
  150. /**
  151. * Visit `node`.
  152. *
  153. * @param {Node} node
  154. * @api public
  155. */
  156. visit: function(node){
  157. var debug = this.debug;
  158. if (debug) {
  159. this.buf.push('jade_debug.unshift({ lineno: ' + node.line
  160. + ', filename: ' + (node.filename
  161. ? JSON.stringify(node.filename)
  162. : 'jade_debug[0].filename')
  163. + ' });');
  164. }
  165. // Massive hack to fix our context
  166. // stack for - else[ if] etc
  167. if (false === node.debug && this.debug) {
  168. this.buf.pop();
  169. this.buf.pop();
  170. }
  171. this.visitNode(node);
  172. if (debug) this.buf.push('jade_debug.shift();');
  173. },
  174. /**
  175. * Visit `node`.
  176. *
  177. * @param {Node} node
  178. * @api public
  179. */
  180. visitNode: function(node){
  181. return this['visit' + node.type](node);
  182. },
  183. /**
  184. * Visit case `node`.
  185. *
  186. * @param {Literal} node
  187. * @api public
  188. */
  189. visitCase: function(node){
  190. var _ = this.withinCase;
  191. this.withinCase = true;
  192. this.buf.push('switch (' + node.expr + '){');
  193. this.visit(node.block);
  194. this.buf.push('}');
  195. this.withinCase = _;
  196. },
  197. /**
  198. * Visit when `node`.
  199. *
  200. * @param {Literal} node
  201. * @api public
  202. */
  203. visitWhen: function(node){
  204. if ('default' == node.expr) {
  205. this.buf.push('default:');
  206. } else {
  207. this.buf.push('case ' + node.expr + ':');
  208. }
  209. this.visit(node.block);
  210. this.buf.push(' break;');
  211. },
  212. /**
  213. * Visit literal `node`.
  214. *
  215. * @param {Literal} node
  216. * @api public
  217. */
  218. visitLiteral: function(node){
  219. this.buffer(node.str);
  220. },
  221. /**
  222. * Visit all nodes in `block`.
  223. *
  224. * @param {Block} block
  225. * @api public
  226. */
  227. visitBlock: function(block){
  228. var len = block.nodes.length
  229. , escape = this.escape
  230. , pp = this.pp
  231. // Pretty print multi-line text
  232. if (pp && len > 1 && !escape && block.nodes[0].isText && block.nodes[1].isText)
  233. this.prettyIndent(1, true);
  234. for (var i = 0; i < len; ++i) {
  235. // Pretty print text
  236. if (pp && i > 0 && !escape && block.nodes[i].isText && block.nodes[i-1].isText)
  237. this.prettyIndent(1, false);
  238. this.visit(block.nodes[i]);
  239. // Multiple text nodes are separated by newlines
  240. if (block.nodes[i+1] && block.nodes[i].isText && block.nodes[i+1].isText)
  241. this.buffer('\n');
  242. }
  243. },
  244. /**
  245. * Visit a mixin's `block` keyword.
  246. *
  247. * @param {MixinBlock} block
  248. * @api public
  249. */
  250. visitMixinBlock: function(block){
  251. if (this.pp) this.buf.push("jade.indent.push('" + Array(this.indents + 1).join(' ') + "');");
  252. this.buf.push('block && block();');
  253. if (this.pp) this.buf.push("jade.indent.pop();");
  254. },
  255. /**
  256. * Visit `doctype`. Sets terse mode to `true` when html 5
  257. * is used, causing self-closing tags to end with ">" vs "/>",
  258. * and boolean attributes are not mirrored.
  259. *
  260. * @param {Doctype} doctype
  261. * @api public
  262. */
  263. visitDoctype: function(doctype){
  264. if (doctype && (doctype.val || !this.doctype)) {
  265. this.setDoctype(doctype.val || 'default');
  266. }
  267. if (this.doctype) this.buffer(this.doctype);
  268. this.hasCompiledDoctype = true;
  269. },
  270. /**
  271. * Visit `mixin`, generating a function that
  272. * may be called within the template.
  273. *
  274. * @param {Mixin} mixin
  275. * @api public
  276. */
  277. visitMixin: function(mixin){
  278. var name = 'jade_mixins[';
  279. var args = mixin.args || '';
  280. var block = mixin.block;
  281. var attrs = mixin.attrs;
  282. var attrsBlocks = mixin.attributeBlocks;
  283. var pp = this.pp;
  284. name += (mixin.name[0]=='#' ? mixin.name.substr(2,mixin.name.length-3):'"'+mixin.name+'"')+']';
  285. if (mixin.call) {
  286. if (pp) this.buf.push("jade.indent.push('" + Array(this.indents + 1).join(' ') + "');")
  287. if (block || attrs.length || attrsBlocks.length) {
  288. this.buf.push(name + '.call({');
  289. if (block) {
  290. this.buf.push('block: function(){');
  291. // Render block with no indents, dynamically added when rendered
  292. this.parentIndents++;
  293. var _indents = this.indents;
  294. this.indents = 0;
  295. this.visit(mixin.block);
  296. this.indents = _indents;
  297. this.parentIndents--;
  298. if (attrs.length || attrsBlocks.length) {
  299. this.buf.push('},');
  300. } else {
  301. this.buf.push('}');
  302. }
  303. }
  304. if (attrsBlocks.length) {
  305. if (attrs.length) {
  306. var val = this.attrs(attrs);
  307. attrsBlocks.unshift(val);
  308. }
  309. this.buf.push('attributes: jade.merge([' + attrsBlocks.join(',') + '])');
  310. } else if (attrs.length) {
  311. var val = this.attrs(attrs);
  312. this.buf.push('attributes: ' + val);
  313. }
  314. if (args) {
  315. this.buf.push('}, ' + args + ');');
  316. } else {
  317. this.buf.push('});');
  318. }
  319. } else {
  320. this.buf.push(name + '(' + args + ');');
  321. }
  322. if (pp) this.buf.push("jade.indent.pop();")
  323. } else {
  324. this.buf.push(name + ' = function(' + args + '){');
  325. this.buf.push('var block = (this && this.block), attributes = (this && this.attributes) || {};');
  326. this.parentIndents++;
  327. this.visit(block);
  328. this.parentIndents--;
  329. this.buf.push('};');
  330. }
  331. },
  332. /**
  333. * Visit `tag` buffering tag markup, generating
  334. * attributes, visiting the `tag`'s code and block.
  335. *
  336. * @param {Tag} tag
  337. * @api public
  338. */
  339. visitTag: function(tag){
  340. this.indents++;
  341. var name = tag.name
  342. , pp = this.pp
  343. , self = this;
  344. function bufferName() {
  345. if (tag.buffer) self.bufferExpression(name);
  346. else self.buffer(name);
  347. }
  348. if ('pre' == tag.name) this.escape = true;
  349. if (!this.hasCompiledTag) {
  350. if (!this.hasCompiledDoctype && 'html' == name) {
  351. this.visitDoctype();
  352. }
  353. this.hasCompiledTag = true;
  354. }
  355. // pretty print
  356. if (pp && !tag.isInline())
  357. this.prettyIndent(0, true);
  358. if ((~selfClosing.indexOf(name) || tag.selfClosing) && !this.xml) {
  359. this.buffer('<');
  360. bufferName();
  361. this.visitAttributes(tag.attrs, tag.attributeBlocks);
  362. this.terse
  363. ? this.buffer('>')
  364. : this.buffer('/>');
  365. // if it is non-empty throw an error
  366. if (tag.block && !(tag.block.type === 'Block' && tag.block.nodes.length === 0)
  367. && tag.block.nodes.some(function (tag) { return tag.type !== 'Text' || !/^\s*$/.test(tag.val)})) {
  368. throw new Error(name + ' is self closing and should not have content.');
  369. }
  370. } else {
  371. // Optimize attributes buffering
  372. this.buffer('<');
  373. bufferName();
  374. this.visitAttributes(tag.attrs, tag.attributeBlocks);
  375. this.buffer('>');
  376. if (tag.code) this.visitCode(tag.code);
  377. this.visit(tag.block);
  378. // pretty print
  379. if (pp && !tag.isInline() && 'pre' != tag.name && !tag.canInline())
  380. this.prettyIndent(0, true);
  381. this.buffer('</');
  382. bufferName();
  383. this.buffer('>');
  384. }
  385. if ('pre' == tag.name) this.escape = false;
  386. this.indents--;
  387. },
  388. /**
  389. * Visit `filter`, throwing when the filter does not exist.
  390. *
  391. * @param {Filter} filter
  392. * @api public
  393. */
  394. visitFilter: function(filter){
  395. var text = filter.block.nodes.map(
  396. function(node){ return node.val; }
  397. ).join('\n');
  398. filter.attrs = filter.attrs || {};
  399. filter.attrs.filename = this.options.filename;
  400. this.buffer(filters(filter.name, text, filter.attrs), true);
  401. },
  402. /**
  403. * Visit `text` node.
  404. *
  405. * @param {Text} text
  406. * @api public
  407. */
  408. visitText: function(text){
  409. this.buffer(text.val, true);
  410. },
  411. /**
  412. * Visit a `comment`, only buffering when the buffer flag is set.
  413. *
  414. * @param {Comment} comment
  415. * @api public
  416. */
  417. visitComment: function(comment){
  418. if (!comment.buffer) return;
  419. if (this.pp) this.prettyIndent(1, true);
  420. this.buffer('<!--' + comment.val + '-->');
  421. },
  422. /**
  423. * Visit a `BlockComment`.
  424. *
  425. * @param {Comment} comment
  426. * @api public
  427. */
  428. visitBlockComment: function(comment){
  429. if (!comment.buffer) return;
  430. if (this.pp) this.prettyIndent(1, true);
  431. this.buffer('<!--' + comment.val);
  432. this.visit(comment.block);
  433. if (this.pp) this.prettyIndent(1, true);
  434. this.buffer('-->');
  435. },
  436. /**
  437. * Visit `code`, respecting buffer / escape flags.
  438. * If the code is followed by a block, wrap it in
  439. * a self-calling function.
  440. *
  441. * @param {Code} code
  442. * @api public
  443. */
  444. visitCode: function(code){
  445. // Wrap code blocks with {}.
  446. // we only wrap unbuffered code blocks ATM
  447. // since they are usually flow control
  448. // Buffer code
  449. if (code.buffer) {
  450. var val = code.val.trimLeft();
  451. val = 'null == (jade.interp = '+val+') ? "" : jade.interp';
  452. if (code.escape) val = 'jade.escape(' + val + ')';
  453. this.bufferExpression(val);
  454. } else {
  455. this.buf.push(code.val);
  456. }
  457. // Block support
  458. if (code.block) {
  459. if (!code.buffer) this.buf.push('{');
  460. this.visit(code.block);
  461. if (!code.buffer) this.buf.push('}');
  462. }
  463. },
  464. /**
  465. * Visit `each` block.
  466. *
  467. * @param {Each} each
  468. * @api public
  469. */
  470. visitEach: function(each){
  471. this.buf.push(''
  472. + '// iterate ' + each.obj + '\n'
  473. + ';(function(){\n'
  474. + ' var $$obj = ' + each.obj + ';\n'
  475. + ' if (\'number\' == typeof $$obj.length) {\n');
  476. if (each.alternative) {
  477. this.buf.push(' if ($$obj.length) {');
  478. }
  479. this.buf.push(''
  480. + ' for (var ' + each.key + ' = 0, $$l = $$obj.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
  481. + ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
  482. this.visit(each.block);
  483. this.buf.push(' }\n');
  484. if (each.alternative) {
  485. this.buf.push(' } else {');
  486. this.visit(each.alternative);
  487. this.buf.push(' }');
  488. }
  489. this.buf.push(''
  490. + ' } else {\n'
  491. + ' var $$l = 0;\n'
  492. + ' for (var ' + each.key + ' in $$obj) {\n'
  493. + ' $$l++;'
  494. + ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
  495. this.visit(each.block);
  496. this.buf.push(' }\n');
  497. if (each.alternative) {
  498. this.buf.push(' if ($$l === 0) {');
  499. this.visit(each.alternative);
  500. this.buf.push(' }');
  501. }
  502. this.buf.push(' }\n}).call(this);\n');
  503. },
  504. /**
  505. * Visit `attrs`.
  506. *
  507. * @param {Array} attrs
  508. * @api public
  509. */
  510. visitAttributes: function(attrs, attributeBlocks){
  511. if (attributeBlocks.length) {
  512. if (attrs.length) {
  513. var val = this.attrs(attrs);
  514. attributeBlocks.unshift(val);
  515. }
  516. this.bufferExpression('jade.attrs(jade.merge([' + attributeBlocks.join(',') + ']), ' + JSON.stringify(this.terse) + ')');
  517. } else if (attrs.length) {
  518. this.attrs(attrs, true);
  519. }
  520. },
  521. /**
  522. * Compile attributes.
  523. */
  524. attrs: function(attrs, buffer){
  525. var buf = [];
  526. var classes = [];
  527. var classEscaping = [];
  528. attrs.forEach(function(attr){
  529. var key = attr.name;
  530. var escaped = attr.escaped;
  531. if (key === 'class') {
  532. classes.push(attr.val);
  533. classEscaping.push(attr.escaped);
  534. } else if (isConstant(attr.val)) {
  535. if (buffer) {
  536. this.buffer(runtime.attr(key, toConstant(attr.val), escaped, this.terse));
  537. } else {
  538. var val = toConstant(attr.val);
  539. if (escaped && !(key.indexOf('data') === 0 && typeof val !== 'string')) {
  540. val = runtime.escape(val);
  541. }
  542. buf.push(JSON.stringify(key) + ': ' + JSON.stringify(val));
  543. }
  544. } else {
  545. if (buffer) {
  546. this.bufferExpression('jade.attr("' + key + '", ' + attr.val + ', ' + JSON.stringify(escaped) + ', ' + JSON.stringify(this.terse) + ')');
  547. } else {
  548. var val = attr.val;
  549. if (escaped && !(key.indexOf('data') === 0)) {
  550. val = 'jade.escape(' + val + ')';
  551. } else if (escaped) {
  552. val = '(typeof (jade.interp = ' + val + ') == "string" ? jade.escape(jade.interp) : jade.interp)"';
  553. }
  554. buf.push(JSON.stringify(key) + ': ' + val);
  555. }
  556. }
  557. }.bind(this));
  558. if (buffer) {
  559. if (classes.every(isConstant)) {
  560. this.buffer(runtime.cls(classes.map(toConstant), classEscaping));
  561. } else {
  562. this.bufferExpression('jade.cls([' + classes.join(',') + '], ' + JSON.stringify(classEscaping) + ')');
  563. }
  564. } else {
  565. if (classes.every(isConstant)) {
  566. classes = JSON.stringify(runtime.joinClasses(classes.map(toConstant).map(runtime.joinClasses).map(function (cls, i) {
  567. return classEscaping[i] ? runtime.escape(cls) : cls;
  568. })));
  569. } else if (classes.length) {
  570. classes = '(jade.interp = ' + JSON.stringify(classEscaping) + ',' +
  571. ' jade.joinClasses([' + classes.join(',') + '].map(jade.joinClasses).map(function (cls, i) {' +
  572. ' return jade.interp[i] ? jade.escape(cls) : cls' +
  573. ' }))' +
  574. ')';
  575. }
  576. if (classes.length)
  577. buf.push('"class": ' + classes);
  578. }
  579. return '{' + buf.join(',') + '}';
  580. }
  581. };
  582. },{"./doctypes":2,"./filters":3,"./nodes":16,"./runtime":24,"./self-closing":25,"./utils":26,"character-parser":33,"constantinople":34}],2:[function(require,module,exports){
  583. 'use strict';
  584. module.exports = {
  585. 'default': '<!DOCTYPE html>'
  586. , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
  587. , 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
  588. , 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
  589. , 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
  590. , '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
  591. , 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
  592. , 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
  593. };
  594. },{}],3:[function(require,module,exports){
  595. 'use strict';
  596. module.exports = filter;
  597. function filter(name, str, options) {
  598. if (typeof filter[name] === 'function') {
  599. var res = filter[name](str, options);
  600. } else {
  601. throw new Error('unknown filter ":' + name + '"');
  602. }
  603. return res;
  604. }
  605. filter.exists = function (name, str, options) {
  606. return typeof filter[name] === 'function';
  607. };
  608. },{}],4:[function(require,module,exports){
  609. 'use strict';
  610. module.exports = [
  611. 'a'
  612. , 'abbr'
  613. , 'acronym'
  614. , 'b'
  615. , 'br'
  616. , 'code'
  617. , 'em'
  618. , 'font'
  619. , 'i'
  620. , 'img'
  621. , 'ins'
  622. , 'kbd'
  623. , 'map'
  624. , 'samp'
  625. , 'small'
  626. , 'span'
  627. , 'strong'
  628. , 'sub'
  629. , 'sup'
  630. ];
  631. },{}],5:[function(require,module,exports){
  632. 'use strict';
  633. /*!
  634. * Jade
  635. * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
  636. * MIT Licensed
  637. */
  638. /**
  639. * Module dependencies.
  640. */
  641. var Parser = require('./parser')
  642. , Lexer = require('./lexer')
  643. , Compiler = require('./compiler')
  644. , runtime = require('./runtime')
  645. , addWith = require('with')
  646. , fs = require('fs');
  647. /**
  648. * Expose self closing tags.
  649. */
  650. exports.selfClosing = require('./self-closing');
  651. /**
  652. * Default supported doctypes.
  653. */
  654. exports.doctypes = require('./doctypes');
  655. /**
  656. * Text filters.
  657. */
  658. exports.filters = require('./filters');
  659. /**
  660. * Utilities.
  661. */
  662. exports.utils = require('./utils');
  663. /**
  664. * Expose `Compiler`.
  665. */
  666. exports.Compiler = Compiler;
  667. /**
  668. * Expose `Parser`.
  669. */
  670. exports.Parser = Parser;
  671. /**
  672. * Expose `Lexer`.
  673. */
  674. exports.Lexer = Lexer;
  675. /**
  676. * Nodes.
  677. */
  678. exports.nodes = require('./nodes');
  679. /**
  680. * Jade runtime helpers.
  681. */
  682. exports.runtime = runtime;
  683. /**
  684. * Template function cache.
  685. */
  686. exports.cache = {};
  687. /**
  688. * Parse the given `str` of jade and return a function body.
  689. *
  690. * @param {String} str
  691. * @param {Object} options
  692. * @return {String}
  693. * @api private
  694. */
  695. function parse(str, options){
  696. try {
  697. // Parse
  698. var parser = new (options.parser || Parser)(str, options.filename, options);
  699. // Compile
  700. var compiler = new (options.compiler || Compiler)(parser.parse(), options)
  701. , js = compiler.compile();
  702. // Debug compiler
  703. if (options.debug) {
  704. console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, ' '));
  705. }
  706. var globals = options.globals && Array.isArray(options.globals) ? options.globals : [];
  707. globals.push('jade');
  708. globals.push('jade_mixins');
  709. globals.push('jade_debug');
  710. globals.push('buf');
  711. return ''
  712. + 'var buf = [];\n'
  713. + 'var jade_mixins = {};\n'
  714. + (options.self
  715. ? 'var self = locals || {};\n' + js
  716. : addWith('locals || {}', '\n' + js, globals)) + ';'
  717. + 'return buf.join("");';
  718. } catch (err) {
  719. parser = parser.context();
  720. runtime.rethrow(err, parser.filename, parser.lexer.lineno, parser.input);
  721. }
  722. }
  723. /**
  724. * Compile a `Function` representation of the given jade `str`.
  725. *
  726. * Options:
  727. *
  728. * - `compileDebug` when `false` debugging code is stripped from the compiled
  729. template, when it is explicitly `true`, the source code is included in
  730. the compiled template for better accuracy.
  731. * - `filename` used to improve errors when `compileDebug` is not `false` and to resolve imports/extends
  732. *
  733. * @param {String} str
  734. * @param {Options} options
  735. * @return {Function}
  736. * @api public
  737. */
  738. exports.compile = function(str, options){
  739. var options = options || {}
  740. , filename = options.filename
  741. ? JSON.stringify(options.filename)
  742. : 'undefined'
  743. , fn;
  744. str = String(str);
  745. if (options.compileDebug !== false) {
  746. fn = [
  747. 'var jade_debug = [{ lineno: 1, filename: ' + filename + ' }];'
  748. , 'try {'
  749. , parse(str, options)
  750. , '} catch (err) {'
  751. , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno' + (options.compileDebug === true ? ',' + JSON.stringify(str) : '') + ');'
  752. , '}'
  753. ].join('\n');
  754. } else {
  755. fn = parse(str, options);
  756. }
  757. fn = new Function('locals, jade', fn)
  758. var res = function(locals){ return fn(locals, Object.create(runtime)) };
  759. if (options.client) {
  760. res.toString = function () {
  761. var err = new Error('The `client` option is deprecated, use `jade.compileClient`');
  762. console.error(err.stack || err.message);
  763. return exports.compileClient(str, options);
  764. };
  765. }
  766. return res;
  767. };
  768. /**
  769. * Compile a JavaScript source representation of the given jade `str`.
  770. *
  771. * Options:
  772. *
  773. * - `compileDebug` When it is `true`, the source code is included in
  774. the compiled template for better error messages.
  775. * - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
  776. *
  777. * @param {String} str
  778. * @param {Options} options
  779. * @return {String}
  780. * @api public
  781. */
  782. exports.compileClient = function(str, options){
  783. var options = options || {}
  784. , filename = options.filename
  785. ? JSON.stringify(options.filename)
  786. : 'undefined'
  787. , fn;
  788. str = String(str);
  789. if (options.compileDebug) {
  790. options.compileDebug = true;
  791. fn = [
  792. 'var jade_debug = [{ lineno: 1, filename: ' + filename + ' }];'
  793. , 'try {'
  794. , parse(str, options)
  795. , '} catch (err) {'
  796. , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno, ' + JSON.stringify(str) + ');'
  797. , '}'
  798. ].join('\n');
  799. } else {
  800. options.compileDebug = false;
  801. fn = parse(str, options);
  802. }
  803. return 'function template(locals) {\n' + fn + '\n}';
  804. };
  805. /**
  806. * Render the given `str` of jade.
  807. *
  808. * Options:
  809. *
  810. * - `cache` enable template caching
  811. * - `filename` filename required for `include` / `extends` and caching
  812. *
  813. * @param {String} str
  814. * @param {Object|Function} options or fn
  815. * @param {Function|undefined} fn
  816. * @returns {String}
  817. * @api public
  818. */
  819. exports.render = function(str, options, fn){
  820. // support callback API
  821. if ('function' == typeof options) {
  822. fn = options, options = undefined;
  823. }
  824. if (typeof fn === 'function') {
  825. var res
  826. try {
  827. res = exports.render(str, options);
  828. } catch (ex) {
  829. return fn(ex);
  830. }
  831. return fn(null, res);
  832. }
  833. options = options || {};
  834. // cache requires .filename
  835. if (options.cache && !options.filename) {
  836. throw new Error('the "filename" option is required for caching');
  837. }
  838. var path = options.filename;
  839. var tmpl = options.cache
  840. ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
  841. : exports.compile(str, options);
  842. return tmpl(options);
  843. };
  844. /**
  845. * Render a Jade file at the given `path`.
  846. *
  847. * @param {String} path
  848. * @param {Object|Function} options or callback
  849. * @param {Function|undefined} fn
  850. * @returns {String}
  851. * @api public
  852. */
  853. exports.renderFile = function(path, options, fn){
  854. // support callback API
  855. if ('function' == typeof options) {
  856. fn = options, options = undefined;
  857. }
  858. if (typeof fn === 'function') {
  859. var res
  860. try {
  861. res = exports.renderFile(path, options);
  862. } catch (ex) {
  863. return fn(ex);
  864. }
  865. return fn(null, res);
  866. }
  867. options = options || {};
  868. var key = path + ':string';
  869. options.filename = path;
  870. var str = options.cache
  871. ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
  872. : fs.readFileSync(path, 'utf8');
  873. return exports.render(str, options);
  874. };
  875. /**
  876. * Compile a Jade file at the given `path` for use on the client.
  877. *
  878. * @param {String} path
  879. * @param {Object} options
  880. * @returns {String}
  881. * @api public
  882. */
  883. exports.compileFileClient = function(path, options){
  884. options = options || {};
  885. var key = path + ':string';
  886. options.filename = path;
  887. var str = options.cache
  888. ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
  889. : fs.readFileSync(path, 'utf8');
  890. return exports.compileClient(str, options);
  891. };
  892. /**
  893. * Express support.
  894. */
  895. exports.__express = exports.renderFile;
  896. },{"./compiler":1,"./doctypes":2,"./filters":3,"./lexer":6,"./nodes":16,"./parser":23,"./runtime":24,"./self-closing":25,"./utils":26,"fs":27,"with":46}],6:[function(require,module,exports){
  897. 'use strict';
  898. var utils = require('./utils');
  899. var characterParser = require('character-parser');
  900. /**
  901. * Initialize `Lexer` with the given `str`.
  902. *
  903. * @param {String} str
  904. * @param {String} filename
  905. * @api private
  906. */
  907. var Lexer = module.exports = function Lexer(str, filename) {
  908. this.input = str.replace(/\r\n|\r/g, '\n');
  909. this.filename = filename;
  910. this.deferredTokens = [];
  911. this.lastIndents = 0;
  912. this.lineno = 1;
  913. this.stash = [];
  914. this.indentStack = [];
  915. this.indentRe = null;
  916. this.pipeless = false;
  917. };
  918. function assertExpression(exp) {
  919. //this verifies that a JavaScript expression is valid
  920. Function('', 'return (' + exp + ')');
  921. }
  922. function assertNestingCorrect(exp) {
  923. //this verifies that code is properly nested, but allows
  924. //invalid JavaScript such as the contents of `attributes`
  925. var res = characterParser(exp)
  926. if (res.isNesting()) {
  927. throw new Error('Nesting must match on expression `' + exp + '`')
  928. }
  929. }
  930. /**
  931. * Lexer prototype.
  932. */
  933. Lexer.prototype = {
  934. /**
  935. * Construct a token with the given `type` and `val`.
  936. *
  937. * @param {String} type
  938. * @param {String} val
  939. * @return {Object}
  940. * @api private
  941. */
  942. tok: function(type, val){
  943. return {
  944. type: type
  945. , line: this.lineno
  946. , val: val
  947. }
  948. },
  949. /**
  950. * Consume the given `len` of input.
  951. *
  952. * @param {Number} len
  953. * @api private
  954. */
  955. consume: function(len){
  956. this.input = this.input.substr(len);
  957. },
  958. /**
  959. * Scan for `type` with the given `regexp`.
  960. *
  961. * @param {String} type
  962. * @param {RegExp} regexp
  963. * @return {Object}
  964. * @api private
  965. */
  966. scan: function(regexp, type){
  967. var captures;
  968. if (captures = regexp.exec(this.input)) {
  969. this.consume(captures[0].length);
  970. return this.tok(type, captures[1]);
  971. }
  972. },
  973. /**
  974. * Defer the given `tok`.
  975. *
  976. * @param {Object} tok
  977. * @api private
  978. */
  979. defer: function(tok){
  980. this.deferredTokens.push(tok);
  981. },
  982. /**
  983. * Lookahead `n` tokens.
  984. *
  985. * @param {Number} n
  986. * @return {Object}
  987. * @api private
  988. */
  989. lookahead: function(n){
  990. var fetch = n - this.stash.length;
  991. while (fetch-- > 0) this.stash.push(this.next());
  992. return this.stash[--n];
  993. },
  994. /**
  995. * Return the indexOf `(` or `{` or `[` / `)` or `}` or `]` delimiters.
  996. *
  997. * @return {Number}
  998. * @api private
  999. */
  1000. bracketExpression: function(skip){
  1001. skip = skip || 0;
  1002. var start = this.input[skip];
  1003. if (start != '(' && start != '{' && start != '[') throw new Error('unrecognized start character');
  1004. var end = ({'(': ')', '{': '}', '[': ']'})[start];
  1005. var range = characterParser.parseMax(this.input, {start: skip + 1});
  1006. if (this.input[range.end] !== end) throw new Error('start character ' + start + ' does not match end character ' + this.input[range.end]);
  1007. return range;
  1008. },
  1009. /**
  1010. * Stashed token.
  1011. */
  1012. stashed: function() {
  1013. return this.stash.length
  1014. && this.stash.shift();
  1015. },
  1016. /**
  1017. * Deferred token.
  1018. */
  1019. deferred: function() {
  1020. return this.deferredTokens.length
  1021. && this.deferredTokens.shift();
  1022. },
  1023. /**
  1024. * end-of-source.
  1025. */
  1026. eos: function() {
  1027. if (this.input.length) return;
  1028. if (this.indentStack.length) {
  1029. this.indentStack.shift();
  1030. return this.tok('outdent');
  1031. } else {
  1032. return this.tok('eos');
  1033. }
  1034. },
  1035. /**
  1036. * Blank line.
  1037. */
  1038. blank: function() {
  1039. var captures;
  1040. if (captures = /^\n *\n/.exec(this.input)) {
  1041. this.consume(captures[0].length - 1);
  1042. ++this.lineno;
  1043. if (this.pipeless) return this.tok('text', '');
  1044. return this.next();
  1045. }
  1046. },
  1047. /**
  1048. * Comment.
  1049. */
  1050. comment: function() {
  1051. var captures;
  1052. if (captures = /^\/\/(-)?([^\n]*)/.exec(this.input)) {
  1053. this.consume(captures[0].length);
  1054. var tok = this.tok('comment', captures[2]);
  1055. tok.buffer = '-' != captures[1];
  1056. return tok;
  1057. }
  1058. },
  1059. /**
  1060. * Interpolated tag.
  1061. */
  1062. interpolation: function() {
  1063. if (/^#\{/.test(this.input)) {
  1064. var match;
  1065. try {
  1066. match = this.bracketExpression(1);
  1067. } catch (ex) {
  1068. return;//not an interpolation expression, just an unmatched open interpolation
  1069. }
  1070. this.consume(match.end + 1);
  1071. return this.tok('interpolation', match.src);
  1072. }
  1073. },
  1074. /**
  1075. * Tag.
  1076. */
  1077. tag: function() {
  1078. var captures;
  1079. if (captures = /^(\w[-:\w]*)(\/?)/.exec(this.input)) {
  1080. this.consume(captures[0].length);
  1081. var tok, name = captures[1];
  1082. if (':' == name[name.length - 1]) {
  1083. name = name.slice(0, -1);
  1084. tok = this.tok('tag', name);
  1085. this.defer(this.tok(':'));
  1086. while (' ' == this.input[0]) this.input = this.input.substr(1);
  1087. } else {
  1088. tok = this.tok('tag', name);
  1089. }
  1090. tok.selfClosing = !! captures[2];
  1091. return tok;
  1092. }
  1093. },
  1094. /**
  1095. * Filter.
  1096. */
  1097. filter: function() {
  1098. return this.scan(/^:([\w\-]+)/, 'filter');
  1099. },
  1100. /**
  1101. * Doctype.
  1102. */
  1103. doctype: function() {
  1104. if (this.scan(/^!!! *([^\n]+)?/, 'doctype')) {
  1105. throw new Error('`!!!` is deprecated, you must now use `doctype`');
  1106. }
  1107. var node = this.scan(/^(?:doctype) *([^\n]+)?/, 'doctype');
  1108. if (node && node.val && node.val.trim() === '5') {
  1109. throw new Error('`doctype 5` is deprecated, you must now use `doctype html`');
  1110. }
  1111. return node;
  1112. },
  1113. /**
  1114. * Id.
  1115. */
  1116. id: function() {
  1117. return this.scan(/^#([\w-]+)/, 'id');
  1118. },
  1119. /**
  1120. * Class.
  1121. */
  1122. className: function() {
  1123. return this.scan(/^\.([\w-]+)/, 'class');
  1124. },
  1125. /**
  1126. * Text.
  1127. */
  1128. text: function() {
  1129. return this.scan(/^(?:\| ?| )([^\n]+)/, 'text') || this.scan(/^(<[^\n]*)/, 'text');
  1130. },
  1131. textFail: function () {
  1132. var tok;
  1133. if (tok = this.scan(/^([^\.\n][^\n]+)/, 'text')) {
  1134. console.warn('Warning: missing space before text for line ' + this.lineno +
  1135. ' of jade file "' + this.filename + '"');
  1136. return tok;
  1137. }
  1138. },
  1139. /**
  1140. * Dot.
  1141. */
  1142. dot: function() {
  1143. return this.scan(/^\./, 'dot');
  1144. },
  1145. /**
  1146. * Extends.
  1147. */
  1148. "extends": function() {
  1149. return this.scan(/^extends? +([^\n]+)/, 'extends');
  1150. },
  1151. /**
  1152. * Block prepend.
  1153. */
  1154. prepend: function() {
  1155. var captures;
  1156. if (captures = /^prepend +([^\n]+)/.exec(this.input)) {
  1157. this.consume(captures[0].length);
  1158. var mode = 'prepend'
  1159. , name = captures[1]
  1160. , tok = this.tok('block', name);
  1161. tok.mode = mode;
  1162. return tok;
  1163. }
  1164. },
  1165. /**
  1166. * Block append.
  1167. */
  1168. append: function() {
  1169. var captures;
  1170. if (captures = /^append +([^\n]+)/.exec(this.input)) {
  1171. this.consume(captures[0].length);
  1172. var mode = 'append'
  1173. , name = captures[1]
  1174. , tok = this.tok('block', name);
  1175. tok.mode = mode;
  1176. return tok;
  1177. }
  1178. },
  1179. /**
  1180. * Block.
  1181. */
  1182. block: function() {
  1183. var captures;
  1184. if (captures = /^block\b *(?:(prepend|append) +)?([^\n]+)/.exec(this.input)) {
  1185. this.consume(captures[0].length);
  1186. var mode = captures[1] || 'replace'
  1187. , name = captures[2]
  1188. , tok = this.tok('block', name);
  1189. tok.mode = mode;
  1190. return tok;
  1191. }
  1192. },
  1193. /**
  1194. * Mixin Block.
  1195. */
  1196. mixinBlock: function() {
  1197. var captures;
  1198. if (captures = /^block\s*(\n|$)/.exec(this.input)) {
  1199. this.consume(captures[0].length - 1);
  1200. return this.tok('mixin-block');
  1201. }
  1202. },
  1203. /**
  1204. * Yield.
  1205. */
  1206. yield: function() {
  1207. return this.scan(/^yield */, 'yield');
  1208. },
  1209. /**
  1210. * Include.
  1211. */
  1212. include: function() {
  1213. return this.scan(/^include +([^\n]+)/, 'include');
  1214. },
  1215. /**
  1216. * Include with filter
  1217. */
  1218. includeFiltered: function() {
  1219. var captures;
  1220. if (captures = /^include:([\w\-]+) +([^\n]+)/.exec(this.input)) {
  1221. this.consume(captures[0].length);
  1222. var filter = captures[1];
  1223. var path = captures[2];
  1224. var tok = this.tok('include', path);
  1225. tok.filter = filter;
  1226. return tok;
  1227. }
  1228. },
  1229. /**
  1230. * Case.
  1231. */
  1232. "case": function() {
  1233. return this.scan(/^case +([^\n]+)/, 'case');
  1234. },
  1235. /**
  1236. * When.
  1237. */
  1238. when: function() {
  1239. return this.scan(/^when +([^:\n]+)/, 'when');
  1240. },
  1241. /**
  1242. * Default.
  1243. */
  1244. "default": function() {
  1245. return this.scan(/^default */, 'default');
  1246. },
  1247. /**
  1248. * Call mixin.
  1249. */
  1250. call: function(){
  1251. var tok, captures;
  1252. if (captures = /^\+(([-\w]+)|(#\{))/.exec(this.input)) {
  1253. // try to consume simple or interpolated call
  1254. if (captures[2]) {
  1255. // simple call
  1256. this.consume(captures[0].length);
  1257. tok = this.tok('call', captures[2]);
  1258. } else {
  1259. // interpolated call
  1260. var match;
  1261. try {
  1262. match = this.bracketExpression(2);
  1263. } catch (ex) {
  1264. return;//not an interpolation expression, just an unmatched open interpolation
  1265. }
  1266. this.consume(match.end + 1);
  1267. assertExpression(match.src);
  1268. tok = this.tok('call', '#{'+match.src+'}');
  1269. }
  1270. // Check for args (not attributes)
  1271. if (captures = /^ *\(/.exec(this.input)) {
  1272. try {
  1273. var range = this.bracketExpression(captures[0].length - 1);
  1274. if (!/^ *[-\w]+ *=/.test(range.src)) { // not attributes
  1275. this.consume(range.end + 1);
  1276. tok.args = range.src;
  1277. }
  1278. } catch (ex) {
  1279. //not a bracket expcetion, just unmatched open parens
  1280. }
  1281. }
  1282. return tok;
  1283. }
  1284. },
  1285. /**
  1286. * Mixin.
  1287. */
  1288. mixin: function(){
  1289. var captures;
  1290. if (captures = /^mixin +([-\w]+)(?: *\((.*)\))? */.exec(this.input)) {
  1291. this.consume(captures[0].length);
  1292. var tok = this.tok('mixin', captures[1]);
  1293. tok.args = captures[2];
  1294. return tok;
  1295. }
  1296. },
  1297. /**
  1298. * Conditional.
  1299. */
  1300. conditional: function() {
  1301. var captures;
  1302. if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) {
  1303. this.consume(captures[0].length);
  1304. var type = captures[1]
  1305. , js = captures[2];
  1306. switch (type) {
  1307. case 'if':
  1308. assertExpression(js)
  1309. js = 'if (' + js + ')';
  1310. break;
  1311. case 'unless':
  1312. assertExpression(js)
  1313. js = 'if (!(' + js + '))';
  1314. break;
  1315. case 'else if':
  1316. assertExpression(js)
  1317. js = 'else if (' + js + ')';
  1318. break;
  1319. case 'else':
  1320. if (js && js.trim()) {
  1321. throw new Error('`else` cannot have a condition, perhaps you meant `else if`');
  1322. }
  1323. js = 'else';
  1324. break;
  1325. }
  1326. return this.tok('code', js);
  1327. }
  1328. },
  1329. /**
  1330. * While.
  1331. */
  1332. "while": function() {
  1333. var captures;
  1334. if (captures = /^while +([^\n]+)/.exec(this.input)) {
  1335. this.consume(captures[0].length);
  1336. assertExpression(captures[1])
  1337. return this.tok('code', 'while (' + captures[1] + ')');
  1338. }
  1339. },
  1340. /**
  1341. * Each.
  1342. */
  1343. each: function() {
  1344. var captures;
  1345. if (captures = /^(?:- *)?(?:each|for) +([a-zA-Z_$][\w$]*)(?: *, *([a-zA-Z_$][\w$]*))? * in *([^\n]+)/.exec(this.input)) {
  1346. this.consume(captures[0].length);
  1347. var tok = this.tok('each', captures[1]);
  1348. tok.key = captures[2] || '$index';
  1349. assertExpression(captures[3])
  1350. tok.code = captures[3];
  1351. return tok;
  1352. }
  1353. },
  1354. /**
  1355. * Code.
  1356. */
  1357. code: function() {
  1358. var captures;
  1359. if (captures = /^(!?=|-)[ \t]*([^\n]+)/.exec(this.input)) {
  1360. this.consume(captures[0].length);
  1361. var flags = captures[1];
  1362. captures[1] = captures[2];
  1363. var tok = this.tok('code', captures[1]);
  1364. tok.escape = flags.charAt(0) === '=';
  1365. tok.buffer = flags.charAt(0) === '=' || flags.charAt(1) === '=';
  1366. if (tok.buffer) assertExpression(captures[1])
  1367. return tok;
  1368. }
  1369. },
  1370. /**
  1371. * Attributes.
  1372. */
  1373. attrs: function() {
  1374. if ('(' == this.input.charAt(0)) {
  1375. var index = this.bracketExpression().end
  1376. , str = this.input.substr(1, index-1)
  1377. , tok = this.tok('attrs');
  1378. assertNestingCorrect(str);
  1379. var quote = '';
  1380. var interpolate = function (attr) {
  1381. return attr.replace(/(\\)?#\{(.+)/g, function(_, escape, expr){
  1382. if (escape) return _;
  1383. try {
  1384. var range = characterParser.parseMax(expr);
  1385. if (expr[range.end] !== '}') return _.substr(0, 2) + interpolate(_.substr(2));
  1386. assertExpression(range.src)
  1387. return quote + " + (" + range.src + ") + " + quote + interpolate(expr.substr(range.end + 1));
  1388. } catch (ex) {
  1389. return _.substr(0, 2) + interpolate(_.substr(2));
  1390. }
  1391. });
  1392. }
  1393. this.consume(index + 1);
  1394. tok.attrs = [];
  1395. var escapedAttr = true
  1396. var key = '';
  1397. var val = '';
  1398. var interpolatable = '';
  1399. var state = characterParser.defaultState();
  1400. var loc = 'key';
  1401. var isEndOfAttribute = function (i) {
  1402. if (key.trim() === '') return false;
  1403. if (i === str.length) return true;
  1404. if (loc === 'key') {
  1405. if (str[i] === ' ' || str[i] === '\n') {
  1406. for (var x = i; x < str.length; x++) {
  1407. if (str[x] != ' ' && str[x] != '\n') {
  1408. if (str[x] === '=' || str[x] === '!' || str[x] === ',') return false;
  1409. else return true;
  1410. }
  1411. }
  1412. }
  1413. return str[i] === ','
  1414. } else if (loc === 'value' && !state.isNesting()) {
  1415. try {
  1416. Function('', 'return (' + val + ');');
  1417. if (str[i] === ' ' || str[i] === '\n') {
  1418. for (var x = i; x < str.length; x++) {
  1419. if (str[x] != ' ' && str[x] != '\n') {
  1420. if (characterParser.isPunctuator(str[x]) && str[x] != '"' && str[x] != "'") return false;
  1421. else return true;
  1422. }
  1423. }
  1424. }
  1425. return str[i] === ',';
  1426. } catch (ex) {
  1427. return false;
  1428. }
  1429. }
  1430. }
  1431. this.lineno += str.split("\n").length - 1;
  1432. for (var i = 0; i <= str.length; i++) {
  1433. if (isEndOfAttribute(i)) {
  1434. val = val.trim();
  1435. if (val) assertExpression(val)
  1436. key = key.trim();
  1437. key = key.replace(/^['"]|['"]$/g, '');
  1438. tok.attrs.push({
  1439. name: key,
  1440. val: '' == val ? true : val,
  1441. escaped: escapedAttr
  1442. });
  1443. key = val = '';
  1444. loc = 'key';
  1445. escapedAttr = false;
  1446. } else {
  1447. switch (loc) {
  1448. case 'key-char':
  1449. if (str[i] === quote) {
  1450. loc = 'key';
  1451. if (i + 1 < str.length && [' ', ',', '!', '=', '\n'].indexOf(str[i + 1]) === -1)
  1452. throw new Error('Unexpected character ' + str[i + 1] + ' expected ` `, `\\n`, `,`, `!` or `=`');
  1453. } else if (loc === 'key-char') {
  1454. key += str[i];
  1455. }
  1456. break;
  1457. case 'key':
  1458. if (key === '' && (str[i] === '"' || str[i] === "'")) {
  1459. loc = 'key-char';
  1460. quote = str[i];
  1461. } else if (str[i] === '!' || str[i] === '=') {
  1462. escapedAttr = str[i] !== '!';
  1463. if (str[i] === '!') i++;
  1464. if (str[i] !== '=') throw new Error('Unexpected character ' + str[i] + ' expected `=`');
  1465. loc = 'value';
  1466. state = characterParser.defaultState();
  1467. } else {
  1468. key += str[i]
  1469. }
  1470. break;
  1471. case 'value':
  1472. state = characterParser.parseChar(str[i], state);
  1473. if (state.isString()) {
  1474. loc = 'string';
  1475. quote = str[i];
  1476. interpolatable = str[i];
  1477. } else {
  1478. val += str[i];
  1479. }
  1480. break;
  1481. case 'string':
  1482. state = characterParser.parseChar(str[i], state);
  1483. interpolatable += str[i];
  1484. if (!state.isString()) {
  1485. loc = 'value';
  1486. val += interpolate(interpolatable);
  1487. }
  1488. break;
  1489. }
  1490. }
  1491. }
  1492. if ('/' == this.input.charAt(0)) {
  1493. this.consume(1);
  1494. tok.selfClosing = true;
  1495. }
  1496. return tok;
  1497. }
  1498. },
  1499. /**
  1500. * &attributes block
  1501. */
  1502. attributesBlock: function () {
  1503. var captures;
  1504. if (/^&attributes\b/.test(this.input)) {
  1505. this.consume(11);
  1506. var args = this.bracketExpression();
  1507. this.consume(args.end + 1);
  1508. return this.tok('&attributes', args.src);
  1509. }
  1510. },
  1511. /**
  1512. * Indent | Outdent | Newline.
  1513. */
  1514. indent: function() {
  1515. var captures, re;
  1516. // established regexp
  1517. if (this.indentRe) {
  1518. captures = this.indentRe.exec(this.input);
  1519. // determine regexp
  1520. } else {
  1521. // tabs
  1522. re = /^\n(\t*) */;
  1523. captures = re.exec(this.input);
  1524. // spaces
  1525. if (captures && !captures[1].length) {
  1526. re = /^\n( *)/;
  1527. captures = re.exec(this.input);
  1528. }
  1529. // established
  1530. if (captures && captures[1].length) this.indentRe = re;
  1531. }
  1532. if (captures) {
  1533. var tok
  1534. , indents = captures[1].length;
  1535. ++this.lineno;
  1536. this.consume(indents + 1);
  1537. if (' ' == this.input[0] || '\t' == this.input[0]) {
  1538. throw new Error('Invalid indentation, you can use tabs or spaces but not both');
  1539. }
  1540. // blank line
  1541. if ('\n' == this.input[0]) return this.tok('newline');
  1542. // outdent
  1543. if (this.indentStack.length && indents < this.indentStack[0]) {
  1544. while (this.indentStack.length && this.indentStack[0] > indents) {
  1545. this.stash.push(this.tok('outdent'));
  1546. this.indentStack.shift();
  1547. }
  1548. tok = this.stash.pop();
  1549. // indent
  1550. } else if (indents && indents != this.indentStack[0]) {
  1551. this.indentStack.unshift(indents);
  1552. tok = this.tok('indent', indents);
  1553. // newline
  1554. } else {
  1555. tok = this.tok('newline');
  1556. }
  1557. return tok;
  1558. }
  1559. },
  1560. /**
  1561. * Pipe-less text consumed only when
  1562. * pipeless is true;
  1563. */
  1564. pipelessText: function() {
  1565. if (this.pipeless) {
  1566. if ('\n' == this.input[0]) return;
  1567. var i = this.input.indexOf('\n');
  1568. if (-1 == i) i = this.input.length;
  1569. var str = this.input.substr(0, i);
  1570. this.consume(str.length);
  1571. return this.tok('text', str);
  1572. }
  1573. },
  1574. /**
  1575. * ':'
  1576. */
  1577. colon: function() {
  1578. return this.scan(/^: */, ':');
  1579. },
  1580. fail: function () {
  1581. if (/^ ($|\n)/.test(this.input)) {
  1582. this.consume(1);
  1583. return this.next();
  1584. }
  1585. throw new Error('unexpected text ' + this.input.substr(0, 5));
  1586. },
  1587. /**
  1588. * Return the next token object, or those
  1589. * previously stashed by lookahead.
  1590. *
  1591. * @return {Object}
  1592. * @api private
  1593. */
  1594. advance: function(){
  1595. return this.stashed()
  1596. || this.next();
  1597. },
  1598. /**
  1599. * Return the next token object.
  1600. *
  1601. * @return {Object}
  1602. * @api private
  1603. */
  1604. next: function() {
  1605. return this.deferred()
  1606. || this.blank()
  1607. || this.eos()
  1608. || this.pipelessText()
  1609. || this.yield()
  1610. || this.doctype()
  1611. || this.interpolation()
  1612. || this["case"]()
  1613. || this.when()
  1614. || this["default"]()
  1615. || this["extends"]()
  1616. || this.append()
  1617. || this.prepend()
  1618. || this.block()
  1619. || this.mixinBlock()
  1620. || this.include()
  1621. || this.includeFiltered()
  1622. || this.mixin()
  1623. || this.call()
  1624. || this.conditional()
  1625. || this.each()
  1626. || this["while"]()
  1627. || this.tag()
  1628. || this.filter()
  1629. || this.code()
  1630. || this.id()
  1631. || this.className()
  1632. || this.attrs()
  1633. || this.attributesBlock()
  1634. || this.indent()
  1635. || this.text()
  1636. || this.comment()
  1637. || this.colon()
  1638. || this.dot()
  1639. || this.textFail()
  1640. || this.fail();
  1641. }
  1642. };
  1643. },{"./utils":26,"character-parser":33}],7:[function(require,module,exports){
  1644. 'use strict';
  1645. var Node = require('./node');
  1646. var Block = require('./block');
  1647. /**
  1648. * Initialize a `Attrs` node.
  1649. *
  1650. * @api public
  1651. */
  1652. var Attrs = module.exports = function Attrs() {
  1653. this.attributeNames = [];
  1654. this.attrs = [];
  1655. this.attributeBlocks = [];
  1656. };
  1657. // Inherit from `Node`.
  1658. Attrs.prototype = Object.create(Node.prototype);
  1659. Attrs.prototype.constructor = Attrs;
  1660. Attrs.prototype.type = 'Attrs';
  1661. /**
  1662. * Set attribute `name` to `val`, keep in mind these become
  1663. * part of a raw js object literal, so to quote a value you must
  1664. * '"quote me"', otherwise or example 'user.name' is literal JavaScript.
  1665. *
  1666. * @param {String} name
  1667. * @param {String} val
  1668. * @param {Boolean} escaped
  1669. * @return {Tag} for chaining
  1670. * @api public
  1671. */
  1672. Attrs.prototype.setAttribute = function(name, val, escaped){
  1673. this.attributeNames = this.attributeNames || [];
  1674. if (name !== 'class' && this.attributeNames.indexOf(name) !== -1) {
  1675. throw new Error('Duplicate attribute "' + name + '" is not allowed.');
  1676. }
  1677. this.attributeNames.push(name);
  1678. this.attrs.push({ name: name, val: val, escaped: escaped });
  1679. return this;
  1680. };
  1681. /**
  1682. * Remove attribute `name` when present.
  1683. *
  1684. * @param {String} name
  1685. * @api public
  1686. */
  1687. Attrs.prototype.removeAttribute = function(name){
  1688. for (var i = 0, len = this.attrs.length; i < len; ++i) {
  1689. if (this.attrs[i] && this.attrs[i].name == name) {
  1690. delete this.attrs[i];
  1691. }
  1692. }
  1693. };
  1694. /**
  1695. * Get attribute value by `name`.
  1696. *
  1697. * @param {String} name
  1698. * @return {String}
  1699. * @api public
  1700. */
  1701. Attrs.prototype.getAttribute = function(name){
  1702. for (var i = 0, len = this.attrs.length; i < len; ++i) {
  1703. if (this.attrs[i] && this.attrs[i].name == name) {
  1704. return this.attrs[i].val;
  1705. }
  1706. }
  1707. };
  1708. Attrs.prototype.addAttributes = function (src) {
  1709. this.attributeBlocks.push(src);
  1710. };
  1711. },{"./block":9,"./node":20}],8:[function(require,module,exports){
  1712. 'use strict';
  1713. var Node = require('./node');
  1714. /**
  1715. * Initialize a `BlockComment` with the given `block`.
  1716. *
  1717. * @param {String} val
  1718. * @param {Block} block
  1719. * @param {Boolean} buffer
  1720. * @api public
  1721. */
  1722. var BlockComment = module.exports = function BlockComment(val, block, buffer) {
  1723. this.block = block;
  1724. this.val = val;
  1725. this.buffer = buffer;
  1726. };
  1727. // Inherit from `Node`.
  1728. BlockComment.prototype = Object.create(Node.prototype);
  1729. BlockComment.prototype.constructor = BlockComment;
  1730. BlockComment.prototype.type = 'BlockComment';
  1731. },{"./node":20}],9:[function(require,module,exports){
  1732. 'use strict';
  1733. var Node = require('./node');
  1734. /**
  1735. * Initialize a new `Block` with an optional `node`.
  1736. *
  1737. * @param {Node} node
  1738. * @api public
  1739. */
  1740. var Block = module.exports = function Block(node){
  1741. this.nodes = [];
  1742. if (node) this.push(node);
  1743. };
  1744. // Inherit from `Node`.
  1745. Block.prototype = Object.create(Node.prototype);
  1746. Block.prototype.constructor = Block;
  1747. Block.prototype.type = 'Block';
  1748. /**
  1749. * Block flag.
  1750. */
  1751. Block.prototype.isBlock = true;
  1752. /**
  1753. * Replace the nodes in `other` with the nodes
  1754. * in `this` block.
  1755. *
  1756. * @param {Block} other
  1757. * @api private
  1758. */
  1759. Block.prototype.replace = function(other){
  1760. other.nodes = this.nodes;
  1761. };
  1762. /**
  1763. * Pust the given `node`.
  1764. *
  1765. * @param {Node} node
  1766. * @return {Number}
  1767. * @api public
  1768. */
  1769. Block.prototype.push = function(node){
  1770. return this.nodes.push(node);
  1771. };
  1772. /**
  1773. * Check if this block is empty.
  1774. *
  1775. * @return {Boolean}
  1776. * @api public
  1777. */
  1778. Block.prototype.isEmpty = function(){
  1779. return 0 == this.nodes.length;
  1780. };
  1781. /**
  1782. * Unshift the given `node`.
  1783. *
  1784. * @param {Node} node
  1785. * @return {Number}
  1786. * @api public
  1787. */
  1788. Block.prototype.unshift = function(node){
  1789. return this.nodes.unshift(node);
  1790. };
  1791. /**
  1792. * Return the "last" block, or the first `yield` node.
  1793. *
  1794. * @return {Block}
  1795. * @api private
  1796. */
  1797. Block.prototype.includeBlock = function(){
  1798. var ret = this
  1799. , node;
  1800. for (var i = 0, len = this.nodes.length; i < len; ++i) {
  1801. node = this.nodes[i];
  1802. if (node.yield) return node;
  1803. else if (node.textOnly) continue;
  1804. else if (node.includeBlock) ret = node.includeBlock();
  1805. else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock();
  1806. if (ret.yield) return ret;
  1807. }
  1808. return ret;
  1809. };
  1810. /**
  1811. * Return a clone of this block.
  1812. *
  1813. * @return {Block}
  1814. * @api private
  1815. */
  1816. Block.prototype.clone = function(){
  1817. var clone = new Block;
  1818. for (var i = 0, len = this.nodes.length; i < len; ++i) {
  1819. clone.push(this.nodes[i].clone());
  1820. }
  1821. return clone;
  1822. };
  1823. },{"./node":20}],10:[function(require,module,exports){
  1824. 'use strict';
  1825. var Node = require('./node');
  1826. /**
  1827. * Initialize a new `Case` with `expr`.
  1828. *
  1829. * @param {String} expr
  1830. * @api public
  1831. */
  1832. var Case = exports = module.exports = function Case(expr, block){
  1833. this.expr = expr;
  1834. this.block = block;
  1835. };
  1836. // Inherit from `Node`.
  1837. Case.prototype = Object.create(Node.prototype);
  1838. Case.prototype.constructor = Case;
  1839. Case.prototype.type = 'Case';
  1840. var When = exports.When = function When(expr, block){
  1841. this.expr = expr;
  1842. this.block = block;
  1843. this.debug = false;
  1844. };
  1845. // Inherit from `Node`.
  1846. When.prototype = Object.create(Node.prototype);
  1847. When.prototype.constructor = When;
  1848. When.prototype.type = 'When';
  1849. },{"./node":20}],11:[function(require,module,exports){
  1850. 'use strict';
  1851. var Node = require('./node');
  1852. /**
  1853. * Initialize a `Code` node with the given code `val`.
  1854. * Code may also be optionally buffered and escaped.
  1855. *
  1856. * @param {String} val
  1857. * @param {Boolean} buffer
  1858. * @param {Boolean} escape
  1859. * @api public
  1860. */
  1861. var Code = module.exports = function Code(val, buffer, escape) {
  1862. this.val = val;
  1863. this.buffer = buffer;
  1864. this.escape = escape;
  1865. if (val.match(/^ *else/)) this.debug = false;
  1866. };
  1867. // Inherit from `Node`.
  1868. Code.prototype = Object.create(Node.prototype);
  1869. Code.prototype.constructor = Code;
  1870. Code.prototype.type = 'Code'; // prevent the minifiers removing this
  1871. },{"./node":20}],12:[function(require,module,exports){
  1872. 'use strict';
  1873. var Node = require('./node');
  1874. /**
  1875. * Initialize a `Comment` with the given `val`, optionally `buffer`,
  1876. * otherwise the comment may render in the output.
  1877. *
  1878. * @param {String} val
  1879. * @param {Boolean} buffer
  1880. * @api public
  1881. */
  1882. var Comment = module.exports = function Comment(val, buffer) {
  1883. this.val = val;
  1884. this.buffer = buffer;
  1885. };
  1886. // Inherit from `Node`.
  1887. Comment.prototype = Object.create(Node.prototype);
  1888. Comment.prototype.constructor = Comment;
  1889. Comment.prototype.type = 'Comment';
  1890. },{"./node":20}],13:[function(require,module,exports){
  1891. 'use strict';
  1892. var Node = require('./node');
  1893. /**
  1894. * Initialize a `Doctype` with the given `val`.
  1895. *
  1896. * @param {String} val
  1897. * @api public
  1898. */
  1899. var Doctype = module.exports = function Doctype(val) {
  1900. this.val = val;
  1901. };
  1902. // Inherit from `Node`.
  1903. Doctype.prototype = Object.create(Node.prototype);
  1904. Doctype.prototype.constructor = Doctype;
  1905. Doctype.prototype.type = 'Doctype';
  1906. },{"./node":20}],14:[function(require,module,exports){
  1907. 'use strict';
  1908. var Node = require('./node');
  1909. /**
  1910. * Initialize an `Each` node, representing iteration
  1911. *
  1912. * @param {String} obj
  1913. * @param {String} val
  1914. * @param {String} key
  1915. * @param {Block} block
  1916. * @api public
  1917. */
  1918. var Each = module.exports = function Each(obj, val, key, block) {
  1919. this.obj = obj;
  1920. this.val = val;
  1921. this.key = key;
  1922. this.block = block;
  1923. };
  1924. // Inherit from `Node`.
  1925. Each.prototype = Object.create(Node.prototype);
  1926. Each.prototype.constructor = Each;
  1927. Each.prototype.type = 'Each';
  1928. },{"./node":20}],15:[function(require,module,exports){
  1929. 'use strict';
  1930. var Node = require('./node')
  1931. var Block = require('./block');
  1932. /**
  1933. * Initialize a `Filter` node with the given
  1934. * filter `name` and `block`.
  1935. *
  1936. * @param {String} name
  1937. * @param {Block|Node} block
  1938. * @api public
  1939. */
  1940. var Filter = module.exports = function Filter(name, block, attrs) {
  1941. this.name = name;
  1942. this.block = block;
  1943. this.attrs = attrs;
  1944. };
  1945. // Inherit from `Node`.
  1946. Filter.prototype = Object.create(Node.prototype);
  1947. Filter.prototype.constructor = Filter;
  1948. Filter.prototype.type = 'Filter';
  1949. },{"./block":9,"./node":20}],16:[function(require,module,exports){
  1950. 'use strict';
  1951. exports.Node = require('./node');
  1952. exports.Tag = require('./tag');
  1953. exports.Code = require('./code');
  1954. exports.Each = require('./each');
  1955. exports.Case = require('./case');
  1956. exports.Text = require('./text');
  1957. exports.Block = require('./block');
  1958. exports.MixinBlock = require('./mixin-block');
  1959. exports.Mixin = require('./mixin');
  1960. exports.Filter = require('./filter');
  1961. exports.Comment = require('./comment');
  1962. exports.Literal = require('./literal');
  1963. exports.BlockComment = require('./block-comment');
  1964. exports.Doctype = require('./doctype');
  1965. },{"./block":9,"./block-comment":8,"./case":10,"./code":11,"./comment":12,"./doctype":13,"./each":14,"./filter":15,"./literal":17,"./mixin":19,"./mixin-block":18,"./node":20,"./tag":21,"./text":22}],17:[function(require,module,exports){
  1966. 'use strict';
  1967. var Node = require('./node');
  1968. /**
  1969. * Initialize a `Literal` node with the given `str.
  1970. *
  1971. * @param {String} str
  1972. * @api public
  1973. */
  1974. var Literal = module.exports = function Literal(str) {
  1975. this.str = str;
  1976. };
  1977. // Inherit from `Node`.
  1978. Literal.prototype = Object.create(Node.prototype);
  1979. Literal.prototype.constructor = Literal;
  1980. Literal.prototype.type = 'Literal';
  1981. },{"./node":20}],18:[function(require,module,exports){
  1982. 'use strict';
  1983. var Node = require('./node');
  1984. /**
  1985. * Initialize a new `Block` with an optional `node`.
  1986. *
  1987. * @param {Node} node
  1988. * @api public
  1989. */
  1990. var MixinBlock = module.exports = function MixinBlock(){};
  1991. // Inherit from `Node`.
  1992. MixinBlock.prototype = Object.create(Node.prototype);
  1993. MixinBlock.prototype.constructor = MixinBlock;
  1994. MixinBlock.prototype.type = 'MixinBlock';
  1995. },{"./node":20}],19:[function(require,module,exports){
  1996. 'use strict';
  1997. var Attrs = require('./attrs');
  1998. /**
  1999. * Initialize a new `Mixin` with `name` and `block`.
  2000. *
  2001. * @param {String} name
  2002. * @param {String} args
  2003. * @param {Block} block
  2004. * @api public
  2005. */
  2006. var Mixin = module.exports = function Mixin(name, args, block, call){
  2007. this.name = name;
  2008. this.args = args;
  2009. this.block = block;
  2010. this.attrs = [];
  2011. this.attributeBlocks = [];
  2012. this.call = call;
  2013. };
  2014. // Inherit from `Attrs`.
  2015. Mixin.prototype = Object.create(Attrs.prototype);
  2016. Mixin.prototype.constructor = Mixin;
  2017. Mixin.prototype.type = 'Mixin';
  2018. },{"./attrs":7}],20:[function(require,module,exports){
  2019. 'use strict';
  2020. var Node = module.exports = function Node(){};
  2021. /**
  2022. * Clone this node (return itself)
  2023. *
  2024. * @return {Node}
  2025. * @api private
  2026. */
  2027. Node.prototype.clone = function(){
  2028. return this;
  2029. };
  2030. Node.prototype.type = '';
  2031. },{}],21:[function(require,module,exports){
  2032. 'use strict';
  2033. var Attrs = require('./attrs');
  2034. var Block = require('./block');
  2035. var inlineTags = require('../inline-tags');
  2036. /**
  2037. * Initialize a `Tag` node with the given tag `name` and optional `block`.
  2038. *
  2039. * @param {String} name
  2040. * @param {Block} block
  2041. * @api public
  2042. */
  2043. var Tag = module.exports = function Tag(name, block) {
  2044. this.name = name;
  2045. this.attrs = [];
  2046. this.attributeBlocks = [];
  2047. this.block = block || new Block;
  2048. };
  2049. // Inherit from `Attrs`.
  2050. Tag.prototype = Object.create(Attrs.prototype);
  2051. Tag.prototype.constructor = Tag;
  2052. Tag.prototype.type = 'Tag';
  2053. /**
  2054. * Clone this tag.
  2055. *
  2056. * @return {Tag}
  2057. * @api private
  2058. */
  2059. Tag.prototype.clone = function(){
  2060. var clone = new Tag(this.name, this.block.clone());
  2061. clone.line = this.line;
  2062. clone.attrs = this.attrs;
  2063. clone.textOnly = this.textOnly;
  2064. return clone;
  2065. };
  2066. /**
  2067. * Check if this tag is an inline tag.
  2068. *
  2069. * @return {Boolean}
  2070. * @api private
  2071. */
  2072. Tag.prototype.isInline = function(){
  2073. return ~inlineTags.indexOf(this.name);
  2074. };
  2075. /**
  2076. * Check if this tag's contents can be inlined. Used for pretty printing.
  2077. *
  2078. * @return {Boolean}
  2079. * @api private
  2080. */
  2081. Tag.prototype.canInline = function(){
  2082. var nodes = this.block.nodes;
  2083. function isInline(node){
  2084. // Recurse if the node is a block
  2085. if (node.isBlock) return node.nodes.every(isInline);
  2086. return node.isText || (node.isInline && node.isInline());
  2087. }
  2088. // Empty tag
  2089. if (!nodes.length) return true;
  2090. // Text-only or inline-only tag
  2091. if (1 == nodes.length) return isInline(nodes[0]);
  2092. // Multi-line inline-only tag
  2093. if (this.block.nodes.every(isInline)) {
  2094. for (var i = 1, len = nodes.length; i < len; ++i) {
  2095. if (nodes[i-1].isText && nodes[i].isText)
  2096. return false;
  2097. }
  2098. return true;
  2099. }
  2100. // Mixed tag
  2101. return false;
  2102. };
  2103. },{"../inline-tags":4,"./attrs":7,"./block":9}],22:[function(require,module,exports){
  2104. 'use strict';
  2105. var Node = require('./node');
  2106. /**
  2107. * Initialize a `Text` node with optional `line`.
  2108. *
  2109. * @param {String} line
  2110. * @api public
  2111. */
  2112. var Text = module.exports = function Text(line) {
  2113. this.val = '';
  2114. if ('string' == typeof line) this.val = line;
  2115. };
  2116. // Inherit from `Node`.
  2117. Text.prototype = Object.create(Node.prototype);
  2118. Text.prototype.constructor = Text;
  2119. Text.prototype.type = 'Text';
  2120. /**
  2121. * Flag as text.
  2122. */
  2123. Text.prototype.isText = true;
  2124. },{"./node":20}],23:[function(require,module,exports){
  2125. 'use strict';
  2126. var Lexer = require('./lexer');
  2127. var nodes = require('./nodes');
  2128. var utils = require('./utils');
  2129. var filters = require('./filters');
  2130. var path = require('path');
  2131. var constantinople = require('constantinople');
  2132. var parseJSExpression = require('character-parser').parseMax;
  2133. var extname = path.extname;
  2134. /**
  2135. * Initialize `Parser` with the given input `str` and `filename`.
  2136. *
  2137. * @param {String} str
  2138. * @param {String} filename
  2139. * @param {Object} options
  2140. * @api public
  2141. */
  2142. var Parser = exports = module.exports = function Parser(str, filename, options){
  2143. //Strip any UTF-8 BOM off of the start of `str`, if it exists.
  2144. this.input = str.replace(/^\uFEFF/, '');
  2145. this.lexer = new Lexer(this.input, filename);
  2146. this.filename = filename;
  2147. this.blocks = {};
  2148. this.mixins = {};
  2149. this.options = options;
  2150. this.contexts = [this];
  2151. this.inMixin = false;
  2152. };
  2153. /**
  2154. * Parser prototype.
  2155. */
  2156. Parser.prototype = {
  2157. /**
  2158. * Save original constructor
  2159. */
  2160. constructor: Parser,
  2161. /**
  2162. * Push `parser` onto the context stack,
  2163. * or pop and return a `Parser`.
  2164. */
  2165. context: function(parser){
  2166. if (parser) {
  2167. this.contexts.push(parser);
  2168. } else {
  2169. return this.contexts.pop();
  2170. }
  2171. },
  2172. /**
  2173. * Return the next token object.
  2174. *
  2175. * @return {Object}
  2176. * @api private
  2177. */
  2178. advance: function(){
  2179. return this.lexer.advance();
  2180. },
  2181. /**
  2182. * Skip `n` tokens.
  2183. *
  2184. * @param {Number} n
  2185. * @api private
  2186. */
  2187. skip: function(n){
  2188. while (n--) this.advance();
  2189. },
  2190. /**
  2191. * Single token lookahead.
  2192. *
  2193. * @return {Object}
  2194. * @api private
  2195. */
  2196. peek: function() {
  2197. return this.lookahead(1);
  2198. },
  2199. /**
  2200. * Return lexer lineno.
  2201. *
  2202. * @return {Number}
  2203. * @api private
  2204. */
  2205. line: function() {
  2206. return this.lexer.lineno;
  2207. },
  2208. /**
  2209. * `n` token lookahead.
  2210. *
  2211. * @param {Number} n
  2212. * @return {Object}
  2213. * @api private
  2214. */
  2215. lookahead: function(n){
  2216. return this.lexer.lookahead(n);
  2217. },
  2218. /**
  2219. * Parse input returning a string of js for evaluation.
  2220. *
  2221. * @return {String}
  2222. * @api public
  2223. */
  2224. parse: function(){
  2225. var block = new nodes.Block, parser;
  2226. block.line = 0;
  2227. block.filename = this.filename;
  2228. while ('eos' != this.peek().type) {
  2229. if ('newline' == this.peek().type) {
  2230. this.advance();
  2231. } else {
  2232. var next = this.peek();
  2233. var expr = this.parseExpr();
  2234. expr.filename = expr.filename || this.filename;
  2235. expr.line = next.line;
  2236. block.push(expr);
  2237. }
  2238. }
  2239. if (parser = this.extending) {
  2240. this.context(parser);
  2241. var ast = parser.parse();
  2242. this.context();
  2243. // hoist mixins
  2244. for (var name in this.mixins)
  2245. ast.unshift(this.mixins[name]);
  2246. return ast;
  2247. }
  2248. return block;
  2249. },
  2250. /**
  2251. * Expect the given type, or throw an exception.
  2252. *
  2253. * @param {String} type
  2254. * @api private
  2255. */
  2256. expect: function(type){
  2257. if (this.peek().type === type) {
  2258. return this.advance();
  2259. } else {
  2260. throw new Error('expected "' + type + '", but got "' + this.peek().type + '"');
  2261. }
  2262. },
  2263. /**
  2264. * Accept the given `type`.
  2265. *
  2266. * @param {String} type
  2267. * @api private
  2268. */
  2269. accept: function(type){
  2270. if (this.peek().type === type) {
  2271. return this.advance();
  2272. }
  2273. },
  2274. /**
  2275. * tag
  2276. * | doctype
  2277. * | mixin
  2278. * | include
  2279. * | filter
  2280. * | comment
  2281. * | text
  2282. * | each
  2283. * | code
  2284. * | yield
  2285. * | id
  2286. * | class
  2287. * | interpolation
  2288. */
  2289. parseExpr: function(){
  2290. switch (this.peek().type) {
  2291. case 'tag':
  2292. return this.parseTag();
  2293. case 'mixin':
  2294. return this.parseMixin();
  2295. case 'block':
  2296. return this.parseBlock();
  2297. case 'mixin-block':
  2298. return this.parseMixinBlock();
  2299. case 'case':
  2300. return this.parseCase();
  2301. case 'when':
  2302. return this.parseWhen();
  2303. case 'default':
  2304. return this.parseDefault();
  2305. case 'extends':
  2306. return this.parseExtends();
  2307. case 'include':
  2308. return this.parseInclude();
  2309. case 'doctype':
  2310. return this.parseDoctype();
  2311. case 'filter':
  2312. return this.parseFilter();
  2313. case 'comment':
  2314. return this.parseComment();
  2315. case 'text':
  2316. return this.parseText();
  2317. case 'each':
  2318. return this.parseEach();
  2319. case 'code':
  2320. return this.parseCode();
  2321. case 'call':
  2322. return this.parseCall();
  2323. case 'interpolation':
  2324. return this.parseInterpolation();
  2325. case 'yield':
  2326. this.advance();
  2327. var block = new nodes.Block;
  2328. block.yield = true;
  2329. return block;
  2330. case 'id':
  2331. case 'class':
  2332. var tok = this.advance();
  2333. this.lexer.defer(this.lexer.tok('tag', 'div'));
  2334. this.lexer.defer(tok);
  2335. return this.parseExpr();
  2336. default:
  2337. throw new Error('unexpected token "' + this.peek().type + '"');
  2338. }
  2339. },
  2340. /**
  2341. * Text
  2342. */
  2343. parseText: function(){
  2344. var tok = this.expect('text');
  2345. var tokens = this.parseTextWithInlineTags(tok.val);
  2346. if (tokens.length === 1) return tokens[0];
  2347. var node = new nodes.Block;
  2348. for (var i = 0; i < tokens.length; i++) {
  2349. node.push(tokens[i]);
  2350. };
  2351. return node;
  2352. },
  2353. /**
  2354. * ':' expr
  2355. * | block
  2356. */
  2357. parseBlockExpansion: function(){
  2358. if (':' == this.peek().type) {
  2359. this.advance();
  2360. return new nodes.Block(this.parseExpr());
  2361. } else {
  2362. return this.block();
  2363. }
  2364. },
  2365. /**
  2366. * case
  2367. */
  2368. parseCase: function(){
  2369. var val = this.expect('case').val;
  2370. var node = new nodes.Case(val);
  2371. node.line = this.line();
  2372. node.block = this.block();
  2373. return node;
  2374. },
  2375. /**
  2376. * when
  2377. */
  2378. parseWhen: function(){
  2379. var val = this.expect('when').val
  2380. return new nodes.Case.When(val, this.parseBlockExpansion());
  2381. },
  2382. /**
  2383. * default
  2384. */
  2385. parseDefault: function(){
  2386. this.expect('default');
  2387. return new nodes.Case.When('default', this.parseBlockExpansion());
  2388. },
  2389. /**
  2390. * code
  2391. */
  2392. parseCode: function(){
  2393. var tok = this.expect('code');
  2394. var node = new nodes.Code(tok.val, tok.buffer, tok.escape);
  2395. var block;
  2396. var i = 1;
  2397. node.line = this.line();
  2398. while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
  2399. block = 'indent' == this.lookahead(i).type;
  2400. if (block) {
  2401. this.skip(i-1);
  2402. node.block = this.block();
  2403. }
  2404. return node;
  2405. },
  2406. /**
  2407. * comment
  2408. */
  2409. parseComment: function(){
  2410. var tok = this.expect('comment');
  2411. var node;
  2412. if ('indent' == this.peek().type) {
  2413. this.lexer.pipeless = true;
  2414. node = new nodes.BlockComment(tok.val, this.parseTextBlock(), tok.buffer);
  2415. this.lexer.pipeless = false;
  2416. } else {
  2417. node = new nodes.Comment(tok.val, tok.buffer);
  2418. }
  2419. node.line = this.line();
  2420. return node;
  2421. },
  2422. /**
  2423. * doctype
  2424. */
  2425. parseDoctype: function(){
  2426. var tok = this.expect('doctype');
  2427. var node = new nodes.Doctype(tok.val);
  2428. node.line = this.line();
  2429. return node;
  2430. },
  2431. /**
  2432. * filter attrs? text-block
  2433. */
  2434. parseFilter: function(){
  2435. var tok = this.expect('filter');
  2436. var attrs = this.accept('attrs');
  2437. var block;
  2438. if ('indent' == this.peek().type) {
  2439. this.lexer.pipeless = true;
  2440. block = this.parseTextBlock();
  2441. this.lexer.pipeless = false;
  2442. } else {
  2443. block = new nodes.Block;
  2444. }
  2445. var options = {};
  2446. if (attrs) {
  2447. attrs.attrs.forEach(function (attribute) {
  2448. options[attribute.name] = constantinople.toConstant(attribute.val);
  2449. });
  2450. }
  2451. var node = new nodes.Filter(tok.val, block, options);
  2452. node.line = this.line();
  2453. return node;
  2454. },
  2455. /**
  2456. * each block
  2457. */
  2458. parseEach: function(){
  2459. var tok = this.expect('each');
  2460. var node = new nodes.Each(tok.code, tok.val, tok.key);
  2461. node.line = this.line();
  2462. node.block = this.block();
  2463. if (this.peek().type == 'code' && this.peek().val == 'else') {
  2464. this.advance();
  2465. node.alternative = this.block();
  2466. }
  2467. return node;
  2468. },
  2469. /**
  2470. * Resolves a path relative to the template for use in
  2471. * includes and extends
  2472. *
  2473. * @param {String} path
  2474. * @param {String} purpose Used in error messages.
  2475. * @return {String}
  2476. * @api private
  2477. */
  2478. resolvePath: function (path, purpose) {
  2479. var p = require('path');
  2480. var dirname = p.dirname;
  2481. var basename = p.basename;
  2482. var join = p.join;
  2483. if (path[0] !== '/' && !this.filename)
  2484. throw new Error('the "filename" option is required to use "' + purpose + '" with "relative" paths');
  2485. if (path[0] === '/' && !this.options.basedir)
  2486. throw new Error('the "basedir" option is required to use "' + purpose + '" with "absolute" paths');
  2487. path = join(path[0] === '/' ? this.options.basedir : dirname(this.filename), path);
  2488. if (basename(path).indexOf('.') === -1) path += '.jade';
  2489. return path;
  2490. },
  2491. /**
  2492. * 'extends' name
  2493. */
  2494. parseExtends: function(){
  2495. var fs = require('fs');
  2496. var path = this.resolvePath(this.expect('extends').val.trim(), 'extends');
  2497. if ('.jade' != path.substr(-5)) path += '.jade';
  2498. var str = fs.readFileSync(path, 'utf8');
  2499. var parser = new this.constructor(str, path, this.options);
  2500. parser.blocks = this.blocks;
  2501. parser.contexts = this.contexts;
  2502. this.extending = parser;
  2503. // TODO: null node
  2504. return new nodes.Literal('');
  2505. },
  2506. /**
  2507. * 'block' name block
  2508. */
  2509. parseBlock: function(){
  2510. var block = this.expect('block');
  2511. var mode = block.mode;
  2512. var name = block.val.trim();
  2513. block = 'indent' == this.peek().type
  2514. ? this.block()
  2515. : new nodes.Block(new nodes.Literal(''));
  2516. var prev = this.blocks[name] || {prepended: [], appended: []}
  2517. if (prev.mode === 'replace') return this.blocks[name] = prev;
  2518. var allNodes = prev.prepended.concat(block.nodes).concat(prev.appended);
  2519. switch (mode) {
  2520. case 'append':
  2521. prev.appended = prev.parser === this ?
  2522. prev.appended.concat(block.nodes) :
  2523. block.nodes.concat(prev.appended);
  2524. break;
  2525. case 'prepend':
  2526. prev.prepended = prev.parser === this ?
  2527. block.nodes.concat(prev.prepended) :
  2528. prev.prepended.concat(block.nodes);
  2529. break;
  2530. }
  2531. block.nodes = allNodes;
  2532. block.appended = prev.appended;
  2533. block.prepended = prev.prepended;
  2534. block.mode = mode;
  2535. block.parser = this;
  2536. return this.blocks[name] = block;
  2537. },
  2538. parseMixinBlock: function () {
  2539. var block = this.expect('mixin-block');
  2540. if (!this.inMixin) {
  2541. throw new Error('Anonymous blocks are not allowed unless they are part of a mixin.');
  2542. }
  2543. return new nodes.MixinBlock();
  2544. },
  2545. /**
  2546. * include block?
  2547. */
  2548. parseInclude: function(){
  2549. var fs = require('fs');
  2550. var tok = this.expect('include');
  2551. var path = this.resolvePath(tok.val.trim(), 'include');
  2552. // has-filter
  2553. if (tok.filter) {
  2554. var str = fs.readFileSync(path, 'utf8').replace(/\r/g, '');
  2555. str = filters(tok.filter, str, { filename: path });
  2556. return new nodes.Literal(str);
  2557. }
  2558. // non-jade
  2559. if ('.jade' != path.substr(-5)) {
  2560. var str = fs.readFileSync(path, 'utf8').replace(/\r/g, '');
  2561. return new nodes.Literal(str);
  2562. }
  2563. var str = fs.readFileSync(path, 'utf8');
  2564. var parser = new this.constructor(str, path, this.options);
  2565. parser.blocks = utils.merge({}, this.blocks);
  2566. parser.mixins = this.mixins;
  2567. this.context(parser);
  2568. var ast = parser.parse();
  2569. this.context();
  2570. ast.filename = path;
  2571. if ('indent' == this.peek().type) {
  2572. ast.includeBlock().push(this.block());
  2573. }
  2574. return ast;
  2575. },
  2576. /**
  2577. * call ident block
  2578. */
  2579. parseCall: function(){
  2580. var tok = this.expect('call');
  2581. var name = tok.val;
  2582. var args = tok.args;
  2583. var mixin = new nodes.Mixin(name, args, new nodes.Block, true);
  2584. this.tag(mixin);
  2585. if (mixin.code) {
  2586. mixin.block.push(mixin.code);
  2587. mixin.code = null;
  2588. }
  2589. if (mixin.block.isEmpty()) mixin.block = null;
  2590. return mixin;
  2591. },
  2592. /**
  2593. * mixin block
  2594. */
  2595. parseMixin: function(){
  2596. var tok = this.expect('mixin');
  2597. var name = tok.val;
  2598. var args = tok.args;
  2599. var mixin;
  2600. // definition
  2601. if ('indent' == this.peek().type) {
  2602. this.inMixin = true;
  2603. mixin = new nodes.Mixin(name, args, this.block(), false);
  2604. this.mixins[name] = mixin;
  2605. this.inMixin = false;
  2606. return mixin;
  2607. // call
  2608. } else {
  2609. return new nodes.Mixin(name, args, null, true);
  2610. }
  2611. },
  2612. parseTextWithInlineTags: function (str) {
  2613. var line = this.line();
  2614. var match = /(\\)?#\[((?:.|\n)*)$/.exec(str);
  2615. if (match) {
  2616. if (match[1]) { // escape
  2617. var text = new nodes.Text(str.substr(0, match.index) + '#[');
  2618. text.line = line;
  2619. var rest = this.parseTextWithInlineTags(match[2]);
  2620. if (rest[0].type === 'Text') {
  2621. text.val += rest[0].val;
  2622. rest.shift();
  2623. }
  2624. return [text].concat(rest);
  2625. } else {
  2626. var text = new nodes.Text(str.substr(0, match.index));
  2627. text.line = line;
  2628. var buffer = [text];
  2629. var rest = match[2];
  2630. var range = parseJSExpression(rest);
  2631. var inner = new Parser(range.src, this.filename, this.options);
  2632. buffer.push(inner.parse());
  2633. return buffer.concat(this.parseTextWithInlineTags(rest.substr(range.end + 1)));
  2634. }
  2635. } else {
  2636. var text = new nodes.Text(str);
  2637. text.line = line;
  2638. return [text];
  2639. }
  2640. },
  2641. /**
  2642. * indent (text | newline)* outdent
  2643. */
  2644. parseTextBlock: function(){
  2645. var block = new nodes.Block;
  2646. block.line = this.line();
  2647. var spaces = this.expect('indent').val;
  2648. if (null == this._spaces) this._spaces = spaces;
  2649. var indent = Array(spaces - this._spaces + 1).join(' ');
  2650. while ('outdent' != this.peek().type) {
  2651. switch (this.peek().type) {
  2652. case 'newline':
  2653. this.advance();
  2654. break;
  2655. case 'indent':
  2656. this.parseTextBlock(true).nodes.forEach(function(node){
  2657. block.push(node);
  2658. });
  2659. break;
  2660. default:
  2661. var texts = this.parseTextWithInlineTags(indent + this.advance().val);
  2662. texts.forEach(function (text) {
  2663. block.push(text);
  2664. });
  2665. }
  2666. }
  2667. if (spaces == this._spaces) this._spaces = null;
  2668. this.expect('outdent');
  2669. return block;
  2670. },
  2671. /**
  2672. * indent expr* outdent
  2673. */
  2674. block: function(){
  2675. var block = new nodes.Block;
  2676. block.line = this.line();
  2677. block.filename = this.filename;
  2678. this.expect('indent');
  2679. while ('outdent' != this.peek().type) {
  2680. if ('newline' == this.peek().type) {
  2681. this.advance();
  2682. } else {
  2683. var expr = this.parseExpr();
  2684. expr.filename = this.filename;
  2685. block.push(expr);
  2686. }
  2687. }
  2688. this.expect('outdent');
  2689. return block;
  2690. },
  2691. /**
  2692. * interpolation (attrs | class | id)* (text | code | ':')? newline* block?
  2693. */
  2694. parseInterpolation: function(){
  2695. var tok = this.advance();
  2696. var tag = new nodes.Tag(tok.val);
  2697. tag.buffer = true;
  2698. return this.tag(tag);
  2699. },
  2700. /**
  2701. * tag (attrs | class | id)* (text | code | ':')? newline* block?
  2702. */
  2703. parseTag: function(){
  2704. var tok = this.advance();
  2705. var tag = new nodes.Tag(tok.val);
  2706. tag.selfClosing = tok.selfClosing;
  2707. return this.tag(tag);
  2708. },
  2709. /**
  2710. * Parse tag.
  2711. */
  2712. tag: function(tag){
  2713. tag.line = this.line();
  2714. var seenAttrs = false;
  2715. // (attrs | class | id)*
  2716. out:
  2717. while (true) {
  2718. switch (this.peek().type) {
  2719. case 'id':
  2720. case 'class':
  2721. var tok = this.advance();
  2722. tag.setAttribute(tok.type, "'" + tok.val + "'");
  2723. continue;
  2724. case 'attrs':
  2725. if (seenAttrs) {
  2726. console.warn('You should not have jade tags with multiple attributes.');
  2727. }
  2728. seenAttrs = true;
  2729. var tok = this.advance();
  2730. var attrs = tok.attrs;
  2731. if (tok.selfClosing) tag.selfClosing = true;
  2732. for (var i = 0; i < attrs.length; i++) {
  2733. tag.setAttribute(attrs[i].name, attrs[i].val, attrs[i].escaped);
  2734. }
  2735. continue;
  2736. case '&attributes':
  2737. var tok = this.advance();
  2738. tag.addAttributes(tok.val);
  2739. break;
  2740. default:
  2741. break out;
  2742. }
  2743. }
  2744. // check immediate '.'
  2745. if ('dot' == this.peek().type) {
  2746. tag.textOnly = true;
  2747. this.advance();
  2748. }
  2749. if (tag.selfClosing
  2750. && ['newline', 'outdent', 'eos'].indexOf(this.peek().type) === -1
  2751. && (this.peek().type !== 'text' || /^\s*$/.text(this.peek().val))) {
  2752. throw new Error(name + ' is self closing and should not have content.');
  2753. }
  2754. // (text | code | ':')?
  2755. switch (this.peek().type) {
  2756. case 'text':
  2757. tag.block.push(this.parseText());
  2758. break;
  2759. case 'code':
  2760. tag.code = this.parseCode();
  2761. break;
  2762. case ':':
  2763. this.advance();
  2764. tag.block = new nodes.Block;
  2765. tag.block.push(this.parseExpr());
  2766. break;
  2767. case 'newline':
  2768. case 'indent':
  2769. case 'outdent':
  2770. case 'eos':
  2771. break;
  2772. default:
  2773. throw new Error('Unexpected token `' + this.peek().type + '` expected `text`, `code`, `:`, `newline` or `eos`')
  2774. }
  2775. // newline*
  2776. while ('newline' == this.peek().type) this.advance();
  2777. // block?
  2778. if ('indent' == this.peek().type) {
  2779. if (tag.textOnly) {
  2780. this.lexer.pipeless = true;
  2781. tag.block = this.parseTextBlock();
  2782. this.lexer.pipeless = false;
  2783. } else {
  2784. var block = this.block();
  2785. if (tag.block) {
  2786. for (var i = 0, len = block.nodes.length; i < len; ++i) {
  2787. tag.block.push(block.nodes[i]);
  2788. }
  2789. } else {
  2790. tag.block = block;
  2791. }
  2792. }
  2793. }
  2794. return tag;
  2795. }
  2796. };
  2797. },{"./filters":3,"./lexer":6,"./nodes":16,"./utils":26,"character-parser":33,"constantinople":34,"fs":27,"path":30}],24:[function(require,module,exports){
  2798. 'use strict';
  2799. /**
  2800. * Merge two attribute objects giving precedence
  2801. * to values in object `b`. Classes are special-cased
  2802. * allowing for arrays and merging/joining appropriately
  2803. * resulting in a string.
  2804. *
  2805. * @param {Object} a
  2806. * @param {Object} b
  2807. * @return {Object} a
  2808. * @api private
  2809. */
  2810. exports.merge = function merge(a, b) {
  2811. if (arguments.length === 1) {
  2812. var attrs = a[0];
  2813. for (var i = 1; i < a.length; i++) {
  2814. attrs = merge(attrs, a[i]);
  2815. }
  2816. return attrs;
  2817. }
  2818. var ac = a['class'];
  2819. var bc = b['class'];
  2820. if (ac || bc) {
  2821. ac = ac || [];
  2822. bc = bc || [];
  2823. if (!Array.isArray(ac)) ac = [ac];
  2824. if (!Array.isArray(bc)) bc = [bc];
  2825. a['class'] = ac.concat(bc).filter(nulls);
  2826. }
  2827. for (var key in b) {
  2828. if (key != 'class') {
  2829. a[key] = b[key];
  2830. }
  2831. }
  2832. return a;
  2833. };
  2834. /**
  2835. * Filter null `val`s.
  2836. *
  2837. * @param {*} val
  2838. * @return {Boolean}
  2839. * @api private
  2840. */
  2841. function nulls(val) {
  2842. return val != null && val !== '';
  2843. }
  2844. /**
  2845. * join array as classes.
  2846. *
  2847. * @param {*} val
  2848. * @return {String}
  2849. */
  2850. exports.joinClasses = joinClasses;
  2851. function joinClasses(val) {
  2852. return Array.isArray(val) ? val.map(joinClasses).filter(nulls).join(' ') : val;
  2853. }
  2854. /**
  2855. * Render the given classes.
  2856. *
  2857. * @param {Array} classes
  2858. * @param {Array.<Boolean>} escaped
  2859. * @return {String}
  2860. */
  2861. exports.cls = function cls(classes, escaped) {
  2862. var buf = [];
  2863. for (var i = 0; i < classes.length; i++) {
  2864. if (escaped && escaped[i]) {
  2865. buf.push(exports.escape(joinClasses([classes[i]])));
  2866. } else {
  2867. buf.push(joinClasses(classes[i]));
  2868. }
  2869. }
  2870. var text = joinClasses(buf);
  2871. if (text.length) {
  2872. return ' class="' + text + '"';
  2873. } else {
  2874. return '';
  2875. }
  2876. };
  2877. /**
  2878. * Render the given attribute.
  2879. *
  2880. * @param {String} key
  2881. * @param {String} val
  2882. * @param {Boolean} escaped
  2883. * @param {Boolean} terse
  2884. * @return {String}
  2885. */
  2886. exports.attr = function attr(key, val, escaped, terse) {
  2887. if ('boolean' == typeof val || null == val) {
  2888. if (val) {
  2889. return ' ' + (terse ? key : key + '="' + key + '"');
  2890. } else {
  2891. return '';
  2892. }
  2893. } else if (0 == key.indexOf('data') && 'string' != typeof val) {
  2894. return ' ' + key + "='" + JSON.stringify(val).replace(/'/g, '&apos;') + "'";
  2895. } else if (escaped) {
  2896. return ' ' + key + '="' + exports.escape(val) + '"';
  2897. } else {
  2898. return ' ' + key + '="' + val + '"';
  2899. }
  2900. };
  2901. /**
  2902. * Render the given attributes object.
  2903. *
  2904. * @param {Object} obj
  2905. * @param {Object} escaped
  2906. * @return {String}
  2907. */
  2908. exports.attrs = function attrs(obj, terse){
  2909. var buf = [];
  2910. var keys = Object.keys(obj);
  2911. if (keys.length) {
  2912. for (var i = 0; i < keys.length; ++i) {
  2913. var key = keys[i]
  2914. , val = obj[key];
  2915. if ('class' == key) {
  2916. if (val = joinClasses(val)) {
  2917. buf.push(' ' + key + '="' + val + '"');
  2918. }
  2919. } else {
  2920. buf.push(exports.attr(key, val, false, terse));
  2921. }
  2922. }
  2923. }
  2924. return buf.join('');
  2925. };
  2926. /**
  2927. * Escape the given string of `html`.
  2928. *
  2929. * @param {String} html
  2930. * @return {String}
  2931. * @api private
  2932. */
  2933. exports.escape = function escape(html){
  2934. var result = String(html)
  2935. .replace(/&/g, '&amp;')
  2936. .replace(/</g, '&lt;')
  2937. .replace(/>/g, '&gt;')
  2938. .replace(/"/g, '&quot;');
  2939. if (result === '' + html) return html;
  2940. else return result;
  2941. };
  2942. /**
  2943. * Re-throw the given `err` in context to the
  2944. * the jade in `filename` at the given `lineno`.
  2945. *
  2946. * @param {Error} err
  2947. * @param {String} filename
  2948. * @param {String} lineno
  2949. * @api private
  2950. */
  2951. exports.rethrow = function rethrow(err, filename, lineno, str){
  2952. if (!(err instanceof Error)) throw err;
  2953. if ((typeof window != 'undefined' || !filename) && !str) {
  2954. err.message += ' on line ' + lineno;
  2955. throw err;
  2956. }
  2957. try {
  2958. str = str || require('fs').readFileSync(filename, 'utf8')
  2959. } catch (ex) {
  2960. rethrow(err, null, lineno)
  2961. }
  2962. var context = 3
  2963. , lines = str.split('\n')
  2964. , start = Math.max(lineno - context, 0)
  2965. , end = Math.min(lines.length, lineno + context);
  2966. // Error context
  2967. var context = lines.slice(start, end).map(function(line, i){
  2968. var curr = i + start + 1;
  2969. return (curr == lineno ? ' > ' : ' ')
  2970. + curr
  2971. + '| '
  2972. + line;
  2973. }).join('\n');
  2974. // Alter exception message
  2975. err.path = filename;
  2976. err.message = (filename || 'Jade') + ':' + lineno
  2977. + '\n' + context + '\n\n' + err.message;
  2978. throw err;
  2979. };
  2980. },{"fs":27}],25:[function(require,module,exports){
  2981. 'use strict';
  2982. // source: http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
  2983. module.exports = [
  2984. 'area'
  2985. , 'base'
  2986. , 'br'
  2987. , 'col'
  2988. , 'embed'
  2989. , 'hr'
  2990. , 'img'
  2991. , 'input'
  2992. , 'keygen'
  2993. , 'link'
  2994. , 'menuitem'
  2995. , 'meta'
  2996. , 'param'
  2997. , 'source'
  2998. , 'track'
  2999. , 'wbr'
  3000. ];
  3001. },{}],26:[function(require,module,exports){
  3002. 'use strict';
  3003. /**
  3004. * Merge `b` into `a`.
  3005. *
  3006. * @param {Object} a
  3007. * @param {Object} b
  3008. * @return {Object}
  3009. * @api public
  3010. */
  3011. exports.merge = function(a, b) {
  3012. for (var key in b) a[key] = b[key];
  3013. return a;
  3014. };
  3015. },{}],27:[function(require,module,exports){
  3016. },{}],28:[function(require,module,exports){
  3017. if (typeof Object.create === 'function') {
  3018. // implementation from standard node.js 'util' module
  3019. module.exports = function inherits(ctor, superCtor) {
  3020. ctor.super_ = superCtor
  3021. ctor.prototype = Object.create(superCtor.prototype, {
  3022. constructor: {
  3023. value: ctor,
  3024. enumerable: false,
  3025. writable: true,
  3026. configurable: true
  3027. }
  3028. });
  3029. };
  3030. } else {
  3031. // old school shim for old browsers
  3032. module.exports = function inherits(ctor, superCtor) {
  3033. ctor.super_ = superCtor
  3034. var TempCtor = function () {}
  3035. TempCtor.prototype = superCtor.prototype
  3036. ctor.prototype = new TempCtor()
  3037. ctor.prototype.constructor = ctor
  3038. }
  3039. }
  3040. },{}],29:[function(require,module,exports){
  3041. // shim for using process in browser
  3042. var process = module.exports = {};
  3043. process.nextTick = (function () {
  3044. var canSetImmediate = typeof window !== 'undefined'
  3045. && window.setImmediate;
  3046. var canPost = typeof window !== 'undefined'
  3047. && window.postMessage && window.addEventListener
  3048. ;
  3049. if (canSetImmediate) {
  3050. return function (f) { return window.setImmediate(f) };
  3051. }
  3052. if (canPost) {
  3053. var queue = [];
  3054. window.addEventListener('message', function (ev) {
  3055. var source = ev.source;
  3056. if ((source === window || source === null) && ev.data === 'process-tick') {
  3057. ev.stopPropagation();
  3058. if (queue.length > 0) {
  3059. var fn = queue.shift();
  3060. fn();
  3061. }
  3062. }
  3063. }, true);
  3064. return function nextTick(fn) {
  3065. queue.push(fn);
  3066. window.postMessage('process-tick', '*');
  3067. };
  3068. }
  3069. return function nextTick(fn) {
  3070. setTimeout(fn, 0);
  3071. };
  3072. })();
  3073. process.title = 'browser';
  3074. process.browser = true;
  3075. process.env = {};
  3076. process.argv = [];
  3077. process.binding = function (name) {
  3078. throw new Error('process.binding is not supported');
  3079. }
  3080. // TODO(shtylman)
  3081. process.cwd = function () { return '/' };
  3082. process.chdir = function (dir) {
  3083. throw new Error('process.chdir is not supported');
  3084. };
  3085. },{}],30:[function(require,module,exports){
  3086. var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
  3087. //
  3088. // Permission is hereby granted, free of charge, to any person obtaining a
  3089. // copy of this software and associated documentation files (the
  3090. // "Software"), to deal in the Software without restriction, including
  3091. // without limitation the rights to use, copy, modify, merge, publish,
  3092. // distribute, sublicense, and/or sell copies of the Software, and to permit
  3093. // persons to whom the Software is furnished to do so, subject to the
  3094. // following conditions:
  3095. //
  3096. // The above copyright notice and this permission notice shall be included
  3097. // in all copies or substantial portions of the Software.
  3098. //
  3099. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  3100. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  3101. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  3102. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  3103. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  3104. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  3105. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  3106. // resolves . and .. elements in a path array with directory names there
  3107. // must be no slashes, empty elements, or device names (c:\) in the array
  3108. // (so also no leading and trailing slashes - it does not distinguish
  3109. // relative and absolute paths)
  3110. function normalizeArray(parts, allowAboveRoot) {
  3111. // if the path tries to go above the root, `up` ends up > 0
  3112. var up = 0;
  3113. for (var i = parts.length - 1; i >= 0; i--) {
  3114. var last = parts[i];
  3115. if (last === '.') {
  3116. parts.splice(i, 1);
  3117. } else if (last === '..') {
  3118. parts.splice(i, 1);
  3119. up++;
  3120. } else if (up) {
  3121. parts.splice(i, 1);
  3122. up--;
  3123. }
  3124. }
  3125. // if the path is allowed to go above the root, restore leading ..s
  3126. if (allowAboveRoot) {
  3127. for (; up--; up) {
  3128. parts.unshift('..');
  3129. }
  3130. }
  3131. return parts;
  3132. }
  3133. // Split a filename into [root, dir, basename, ext], unix version
  3134. // 'root' is just a slash, or nothing.
  3135. var splitPathRe =
  3136. /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  3137. var splitPath = function(filename) {
  3138. return splitPathRe.exec(filename).slice(1);
  3139. };
  3140. // path.resolve([from ...], to)
  3141. // posix version
  3142. exports.resolve = function() {
  3143. var resolvedPath = '',
  3144. resolvedAbsolute = false;
  3145. for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
  3146. var path = (i >= 0) ? arguments[i] : process.cwd();
  3147. // Skip empty and invalid entries
  3148. if (typeof path !== 'string') {
  3149. throw new TypeError('Arguments to path.resolve must be strings');
  3150. } else if (!path) {
  3151. continue;
  3152. }
  3153. resolvedPath = path + '/' + resolvedPath;
  3154. resolvedAbsolute = path.charAt(0) === '/';
  3155. }
  3156. // At this point the path should be resolved to a full absolute path, but
  3157. // handle relative paths to be safe (might happen when process.cwd() fails)
  3158. // Normalize the path
  3159. resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
  3160. return !!p;
  3161. }), !resolvedAbsolute).join('/');
  3162. return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
  3163. };
  3164. // path.normalize(path)
  3165. // posix version
  3166. exports.normalize = function(path) {
  3167. var isAbsolute = exports.isAbsolute(path),
  3168. trailingSlash = substr(path, -1) === '/';
  3169. // Normalize the path
  3170. path = normalizeArray(filter(path.split('/'), function(p) {
  3171. return !!p;
  3172. }), !isAbsolute).join('/');
  3173. if (!path && !isAbsolute) {
  3174. path = '.';
  3175. }
  3176. if (path && trailingSlash) {
  3177. path += '/';
  3178. }
  3179. return (isAbsolute ? '/' : '') + path;
  3180. };
  3181. // posix version
  3182. exports.isAbsolute = function(path) {
  3183. return path.charAt(0) === '/';
  3184. };
  3185. // posix version
  3186. exports.join = function() {
  3187. var paths = Array.prototype.slice.call(arguments, 0);
  3188. return exports.normalize(filter(paths, function(p, index) {
  3189. if (typeof p !== 'string') {
  3190. throw new TypeError('Arguments to path.join must be strings');
  3191. }
  3192. return p;
  3193. }).join('/'));
  3194. };
  3195. // path.relative(from, to)
  3196. // posix version
  3197. exports.relative = function(from, to) {
  3198. from = exports.resolve(from).substr(1);
  3199. to = exports.resolve(to).substr(1);
  3200. function trim(arr) {
  3201. var start = 0;
  3202. for (; start < arr.length; start++) {
  3203. if (arr[start] !== '') break;
  3204. }
  3205. var end = arr.length - 1;
  3206. for (; end >= 0; end--) {
  3207. if (arr[end] !== '') break;
  3208. }
  3209. if (start > end) return [];
  3210. return arr.slice(start, end - start + 1);
  3211. }
  3212. var fromParts = trim(from.split('/'));
  3213. var toParts = trim(to.split('/'));
  3214. var length = Math.min(fromParts.length, toParts.length);
  3215. var samePartsLength = length;
  3216. for (var i = 0; i < length; i++) {
  3217. if (fromParts[i] !== toParts[i]) {
  3218. samePartsLength = i;
  3219. break;
  3220. }
  3221. }
  3222. var outputParts = [];
  3223. for (var i = samePartsLength; i < fromParts.length; i++) {
  3224. outputParts.push('..');
  3225. }
  3226. outputParts = outputParts.concat(toParts.slice(samePartsLength));
  3227. return outputParts.join('/');
  3228. };
  3229. exports.sep = '/';
  3230. exports.delimiter = ':';
  3231. exports.dirname = function(path) {
  3232. var result = splitPath(path),
  3233. root = result[0],
  3234. dir = result[1];
  3235. if (!root && !dir) {
  3236. // No dirname whatsoever
  3237. return '.';
  3238. }
  3239. if (dir) {
  3240. // It has a dirname, strip trailing slash
  3241. dir = dir.substr(0, dir.length - 1);
  3242. }
  3243. return root + dir;
  3244. };
  3245. exports.basename = function(path, ext) {
  3246. var f = splitPath(path)[2];
  3247. // TODO: make this comparison case-insensitive on windows?
  3248. if (ext && f.substr(-1 * ext.length) === ext) {
  3249. f = f.substr(0, f.length - ext.length);
  3250. }
  3251. return f;
  3252. };
  3253. exports.extname = function(path) {
  3254. return splitPath(path)[3];
  3255. };
  3256. function filter (xs, f) {
  3257. if (xs.filter) return xs.filter(f);
  3258. var res = [];
  3259. for (var i = 0; i < xs.length; i++) {
  3260. if (f(xs[i], i, xs)) res.push(xs[i]);
  3261. }
  3262. return res;
  3263. }
  3264. // String.prototype.substr - negative index don't work in IE8
  3265. var substr = 'ab'.substr(-1) === 'b'
  3266. ? function (str, start, len) { return str.substr(start, len) }
  3267. : function (str, start, len) {
  3268. if (start < 0) start = str.length + start;
  3269. return str.substr(start, len);
  3270. }
  3271. ;
  3272. },{"__browserify_process":29}],31:[function(require,module,exports){
  3273. module.exports = function isBuffer(arg) {
  3274. return arg && typeof arg === 'object'
  3275. && typeof arg.copy === 'function'
  3276. && typeof arg.fill === 'function'
  3277. && typeof arg.readUInt8 === 'function';
  3278. }
  3279. },{}],32:[function(require,module,exports){
  3280. var process=require("__browserify_process"),global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};// Copyright Joyent, Inc. and other Node contributors.
  3281. //
  3282. // Permission is hereby granted, free of charge, to any person obtaining a
  3283. // copy of this software and associated documentation files (the
  3284. // "Software"), to deal in the Software without restriction, including
  3285. // without limitation the rights to use, copy, modify, merge, publish,
  3286. // distribute, sublicense, and/or sell copies of the Software, and to permit
  3287. // persons to whom the Software is furnished to do so, subject to the
  3288. // following conditions:
  3289. //
  3290. // The above copyright notice and this permission notice shall be included
  3291. // in all copies or substantial portions of the Software.
  3292. //
  3293. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  3294. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  3295. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  3296. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  3297. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  3298. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  3299. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  3300. var formatRegExp = /%[sdj%]/g;
  3301. exports.format = function(f) {
  3302. if (!isString(f)) {
  3303. var objects = [];
  3304. for (var i = 0; i < arguments.length; i++) {
  3305. objects.push(inspect(arguments[i]));
  3306. }
  3307. return objects.join(' ');
  3308. }
  3309. var i = 1;
  3310. var args = arguments;
  3311. var len = args.length;
  3312. var str = String(f).replace(formatRegExp, function(x) {
  3313. if (x === '%%') return '%';
  3314. if (i >= len) return x;
  3315. switch (x) {
  3316. case '%s': return String(args[i++]);
  3317. case '%d': return Number(args[i++]);
  3318. case '%j':
  3319. try {
  3320. return JSON.stringify(args[i++]);
  3321. } catch (_) {
  3322. return '[Circular]';
  3323. }
  3324. default:
  3325. return x;
  3326. }
  3327. });
  3328. for (var x = args[i]; i < len; x = args[++i]) {
  3329. if (isNull(x) || !isObject(x)) {
  3330. str += ' ' + x;
  3331. } else {
  3332. str += ' ' + inspect(x);
  3333. }
  3334. }
  3335. return str;
  3336. };
  3337. // Mark that a method should not be used.
  3338. // Returns a modified function which warns once by default.
  3339. // If --no-deprecation is set, then it is a no-op.
  3340. exports.deprecate = function(fn, msg) {
  3341. // Allow for deprecating things in the process of starting up.
  3342. if (isUndefined(global.process)) {
  3343. return function() {
  3344. return exports.deprecate(fn, msg).apply(this, arguments);
  3345. };
  3346. }
  3347. if (process.noDeprecation === true) {
  3348. return fn;
  3349. }
  3350. var warned = false;
  3351. function deprecated() {
  3352. if (!warned) {
  3353. if (process.throwDeprecation) {
  3354. throw new Error(msg);
  3355. } else if (process.traceDeprecation) {
  3356. console.trace(msg);
  3357. } else {
  3358. console.error(msg);
  3359. }
  3360. warned = true;
  3361. }
  3362. return fn.apply(this, arguments);
  3363. }
  3364. return deprecated;
  3365. };
  3366. var debugs = {};
  3367. var debugEnviron;
  3368. exports.debuglog = function(set) {
  3369. if (isUndefined(debugEnviron))
  3370. debugEnviron = process.env.NODE_DEBUG || '';
  3371. set = set.toUpperCase();
  3372. if (!debugs[set]) {
  3373. if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
  3374. var pid = process.pid;
  3375. debugs[set] = function() {
  3376. var msg = exports.format.apply(exports, arguments);
  3377. console.error('%s %d: %s', set, pid, msg);
  3378. };
  3379. } else {
  3380. debugs[set] = function() {};
  3381. }
  3382. }
  3383. return debugs[set];
  3384. };
  3385. /**
  3386. * Echos the value of a value. Trys to print the value out
  3387. * in the best way possible given the different types.
  3388. *
  3389. * @param {Object} obj The object to print out.
  3390. * @param {Object} opts Optional options object that alters the output.
  3391. */
  3392. /* legacy: obj, showHidden, depth, colors*/
  3393. function inspect(obj, opts) {
  3394. // default options
  3395. var ctx = {
  3396. seen: [],
  3397. stylize: stylizeNoColor
  3398. };
  3399. // legacy...
  3400. if (arguments.length >= 3) ctx.depth = arguments[2];
  3401. if (arguments.length >= 4) ctx.colors = arguments[3];
  3402. if (isBoolean(opts)) {
  3403. // legacy...
  3404. ctx.showHidden = opts;
  3405. } else if (opts) {
  3406. // got an "options" object
  3407. exports._extend(ctx, opts);
  3408. }
  3409. // set default options
  3410. if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
  3411. if (isUndefined(ctx.depth)) ctx.depth = 2;
  3412. if (isUndefined(ctx.colors)) ctx.colors = false;
  3413. if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
  3414. if (ctx.colors) ctx.stylize = stylizeWithColor;
  3415. return formatValue(ctx, obj, ctx.depth);
  3416. }
  3417. exports.inspect = inspect;
  3418. // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
  3419. inspect.colors = {
  3420. 'bold' : [1, 22],
  3421. 'italic' : [3, 23],
  3422. 'underline' : [4, 24],
  3423. 'inverse' : [7, 27],
  3424. 'white' : [37, 39],
  3425. 'grey' : [90, 39],
  3426. 'black' : [30, 39],
  3427. 'blue' : [34, 39],
  3428. 'cyan' : [36, 39],
  3429. 'green' : [32, 39],
  3430. 'magenta' : [35, 39],
  3431. 'red' : [31, 39],
  3432. 'yellow' : [33, 39]
  3433. };
  3434. // Don't use 'blue' not visible on cmd.exe
  3435. inspect.styles = {
  3436. 'special': 'cyan',
  3437. 'number': 'yellow',
  3438. 'boolean': 'yellow',
  3439. 'undefined': 'grey',
  3440. 'null': 'bold',
  3441. 'string': 'green',
  3442. 'date': 'magenta',
  3443. // "name": intentionally not styling
  3444. 'regexp': 'red'
  3445. };
  3446. function stylizeWithColor(str, styleType) {
  3447. var style = inspect.styles[styleType];
  3448. if (style) {
  3449. return '\u001b[' + inspect.colors[style][0] + 'm' + str +
  3450. '\u001b[' + inspect.colors[style][1] + 'm';
  3451. } else {
  3452. return str;
  3453. }
  3454. }
  3455. function stylizeNoColor(str, styleType) {
  3456. return str;
  3457. }
  3458. function arrayToHash(array) {
  3459. var hash = {};
  3460. array.forEach(function(val, idx) {
  3461. hash[val] = true;
  3462. });
  3463. return hash;
  3464. }
  3465. function formatValue(ctx, value, recurseTimes) {
  3466. // Provide a hook for user-specified inspect functions.
  3467. // Check that value is an object with an inspect function on it
  3468. if (ctx.customInspect &&
  3469. value &&
  3470. isFunction(value.inspect) &&
  3471. // Filter out the util module, it's inspect function is special
  3472. value.inspect !== exports.inspect &&
  3473. // Also filter out any prototype objects using the circular check.
  3474. !(value.constructor && value.constructor.prototype === value)) {
  3475. var ret = value.inspect(recurseTimes, ctx);
  3476. if (!isString(ret)) {
  3477. ret = formatValue(ctx, ret, recurseTimes);
  3478. }
  3479. return ret;
  3480. }
  3481. // Primitive types cannot have properties
  3482. var primitive = formatPrimitive(ctx, value);
  3483. if (primitive) {
  3484. return primitive;
  3485. }
  3486. // Look up the keys of the object.
  3487. var keys = Object.keys(value);
  3488. var visibleKeys = arrayToHash(keys);
  3489. if (ctx.showHidden) {
  3490. keys = Object.getOwnPropertyNames(value);
  3491. }
  3492. // IE doesn't make error fields non-enumerable
  3493. // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
  3494. if (isError(value)
  3495. && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
  3496. return formatError(value);
  3497. }
  3498. // Some type of object without properties can be shortcutted.
  3499. if (keys.length === 0) {
  3500. if (isFunction(value)) {
  3501. var name = value.name ? ': ' + value.name : '';
  3502. return ctx.stylize('[Function' + name + ']', 'special');
  3503. }
  3504. if (isRegExp(value)) {
  3505. return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
  3506. }
  3507. if (isDate(value)) {
  3508. return ctx.stylize(Date.prototype.toString.call(value), 'date');
  3509. }
  3510. if (isError(value)) {
  3511. return formatError(value);
  3512. }
  3513. }
  3514. var base = '', array = false, braces = ['{', '}'];
  3515. // Make Array say that they are Array
  3516. if (isArray(value)) {
  3517. array = true;
  3518. braces = ['[', ']'];
  3519. }
  3520. // Make functions say that they are functions
  3521. if (isFunction(value)) {
  3522. var n = value.name ? ': ' + value.name : '';
  3523. base = ' [Function' + n + ']';
  3524. }
  3525. // Make RegExps say that they are RegExps
  3526. if (isRegExp(value)) {
  3527. base = ' ' + RegExp.prototype.toString.call(value);
  3528. }
  3529. // Make dates with properties first say the date
  3530. if (isDate(value)) {
  3531. base = ' ' + Date.prototype.toUTCString.call(value);
  3532. }
  3533. // Make error with message first say the error
  3534. if (isError(value)) {
  3535. base = ' ' + formatError(value);
  3536. }
  3537. if (keys.length === 0 && (!array || value.length == 0)) {
  3538. return braces[0] + base + braces[1];
  3539. }
  3540. if (recurseTimes < 0) {
  3541. if (isRegExp(value)) {
  3542. return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
  3543. } else {
  3544. return ctx.stylize('[Object]', 'special');
  3545. }
  3546. }
  3547. ctx.seen.push(value);
  3548. var output;
  3549. if (array) {
  3550. output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
  3551. } else {
  3552. output = keys.map(function(key) {
  3553. return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
  3554. });
  3555. }
  3556. ctx.seen.pop();
  3557. return reduceToSingleString(output, base, braces);
  3558. }
  3559. function formatPrimitive(ctx, value) {
  3560. if (isUndefined(value))
  3561. return ctx.stylize('undefined', 'undefined');
  3562. if (isString(value)) {
  3563. var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
  3564. .replace(/'/g, "\\'")
  3565. .replace(/\\"/g, '"') + '\'';
  3566. return ctx.stylize(simple, 'string');
  3567. }
  3568. if (isNumber(value))
  3569. return ctx.stylize('' + value, 'number');
  3570. if (isBoolean(value))
  3571. return ctx.stylize('' + value, 'boolean');
  3572. // For some reason typeof null is "object", so special case here.
  3573. if (isNull(value))
  3574. return ctx.stylize('null', 'null');
  3575. }
  3576. function formatError(value) {
  3577. return '[' + Error.prototype.toString.call(value) + ']';
  3578. }
  3579. function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
  3580. var output = [];
  3581. for (var i = 0, l = value.length; i < l; ++i) {
  3582. if (hasOwnProperty(value, String(i))) {
  3583. output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
  3584. String(i), true));
  3585. } else {
  3586. output.push('');
  3587. }
  3588. }
  3589. keys.forEach(function(key) {
  3590. if (!key.match(/^\d+$/)) {
  3591. output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
  3592. key, true));
  3593. }
  3594. });
  3595. return output;
  3596. }
  3597. function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
  3598. var name, str, desc;
  3599. desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
  3600. if (desc.get) {
  3601. if (desc.set) {
  3602. str = ctx.stylize('[Getter/Setter]', 'special');
  3603. } else {
  3604. str = ctx.stylize('[Getter]', 'special');
  3605. }
  3606. } else {
  3607. if (desc.set) {
  3608. str = ctx.stylize('[Setter]', 'special');
  3609. }
  3610. }
  3611. if (!hasOwnProperty(visibleKeys, key)) {
  3612. name = '[' + key + ']';
  3613. }
  3614. if (!str) {
  3615. if (ctx.seen.indexOf(desc.value) < 0) {
  3616. if (isNull(recurseTimes)) {
  3617. str = formatValue(ctx, desc.value, null);
  3618. } else {
  3619. str = formatValue(ctx, desc.value, recurseTimes - 1);
  3620. }
  3621. if (str.indexOf('\n') > -1) {
  3622. if (array) {
  3623. str = str.split('\n').map(function(line) {
  3624. return ' ' + line;
  3625. }).join('\n').substr(2);
  3626. } else {
  3627. str = '\n' + str.split('\n').map(function(line) {
  3628. return ' ' + line;
  3629. }).join('\n');
  3630. }
  3631. }
  3632. } else {
  3633. str = ctx.stylize('[Circular]', 'special');
  3634. }
  3635. }
  3636. if (isUndefined(name)) {
  3637. if (array && key.match(/^\d+$/)) {
  3638. return str;
  3639. }
  3640. name = JSON.stringify('' + key);
  3641. if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
  3642. name = name.substr(1, name.length - 2);
  3643. name = ctx.stylize(name, 'name');
  3644. } else {
  3645. name = name.replace(/'/g, "\\'")
  3646. .replace(/\\"/g, '"')
  3647. .replace(/(^"|"$)/g, "'");
  3648. name = ctx.stylize(name, 'string');
  3649. }
  3650. }
  3651. return name + ': ' + str;
  3652. }
  3653. function reduceToSingleString(output, base, braces) {
  3654. var numLinesEst = 0;
  3655. var length = output.reduce(function(prev, cur) {
  3656. numLinesEst++;
  3657. if (cur.indexOf('\n') >= 0) numLinesEst++;
  3658. return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
  3659. }, 0);
  3660. if (length > 60) {
  3661. return braces[0] +
  3662. (base === '' ? '' : base + '\n ') +
  3663. ' ' +
  3664. output.join(',\n ') +
  3665. ' ' +
  3666. braces[1];
  3667. }
  3668. return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
  3669. }
  3670. // NOTE: These type checking functions intentionally don't use `instanceof`
  3671. // because it is fragile and can be easily faked with `Object.create()`.
  3672. function isArray(ar) {
  3673. return Array.isArray(ar);
  3674. }
  3675. exports.isArray = isArray;
  3676. function isBoolean(arg) {
  3677. return typeof arg === 'boolean';
  3678. }
  3679. exports.isBoolean = isBoolean;
  3680. function isNull(arg) {
  3681. return arg === null;
  3682. }
  3683. exports.isNull = isNull;
  3684. function isNullOrUndefined(arg) {
  3685. return arg == null;
  3686. }
  3687. exports.isNullOrUndefined = isNullOrUndefined;
  3688. function isNumber(arg) {
  3689. return typeof arg === 'number';
  3690. }
  3691. exports.isNumber = isNumber;
  3692. function isString(arg) {
  3693. return typeof arg === 'string';
  3694. }
  3695. exports.isString = isString;
  3696. function isSymbol(arg) {
  3697. return typeof arg === 'symbol';
  3698. }
  3699. exports.isSymbol = isSymbol;
  3700. function isUndefined(arg) {
  3701. return arg === void 0;
  3702. }
  3703. exports.isUndefined = isUndefined;
  3704. function isRegExp(re) {
  3705. return isObject(re) && objectToString(re) === '[object RegExp]';
  3706. }
  3707. exports.isRegExp = isRegExp;
  3708. function isObject(arg) {
  3709. return typeof arg === 'object' && arg !== null;
  3710. }
  3711. exports.isObject = isObject;
  3712. function isDate(d) {
  3713. return isObject(d) && objectToString(d) === '[object Date]';
  3714. }
  3715. exports.isDate = isDate;
  3716. function isError(e) {
  3717. return isObject(e) &&
  3718. (objectToString(e) === '[object Error]' || e instanceof Error);
  3719. }
  3720. exports.isError = isError;
  3721. function isFunction(arg) {
  3722. return typeof arg === 'function';
  3723. }
  3724. exports.isFunction = isFunction;
  3725. function isPrimitive(arg) {
  3726. return arg === null ||
  3727. typeof arg === 'boolean' ||
  3728. typeof arg === 'number' ||
  3729. typeof arg === 'string' ||
  3730. typeof arg === 'symbol' || // ES6 symbol
  3731. typeof arg === 'undefined';
  3732. }
  3733. exports.isPrimitive = isPrimitive;
  3734. exports.isBuffer = require('./support/isBuffer');
  3735. function objectToString(o) {
  3736. return Object.prototype.toString.call(o);
  3737. }
  3738. function pad(n) {
  3739. return n < 10 ? '0' + n.toString(10) : n.toString(10);
  3740. }
  3741. var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
  3742. 'Oct', 'Nov', 'Dec'];
  3743. // 26 Feb 16:19:34
  3744. function timestamp() {
  3745. var d = new Date();
  3746. var time = [pad(d.getHours()),
  3747. pad(d.getMinutes()),
  3748. pad(d.getSeconds())].join(':');
  3749. return [d.getDate(), months[d.getMonth()], time].join(' ');
  3750. }
  3751. // log is just a thin wrapper to console.log that prepends a timestamp
  3752. exports.log = function() {
  3753. console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
  3754. };
  3755. /**
  3756. * Inherit the prototype methods from one constructor into another.
  3757. *
  3758. * The Function.prototype.inherits from lang.js rewritten as a standalone
  3759. * function (not on Function.prototype). NOTE: If this file is to be loaded
  3760. * during bootstrapping this function needs to be rewritten using some native
  3761. * functions as prototype setup using normal JavaScript does not work as
  3762. * expected during bootstrapping (see mirror.js in r114903).
  3763. *
  3764. * @param {function} ctor Constructor function which needs to inherit the
  3765. * prototype.
  3766. * @param {function} superCtor Constructor function to inherit prototype from.
  3767. */
  3768. exports.inherits = require('inherits');
  3769. exports._extend = function(origin, add) {
  3770. // Don't do anything if add isn't an object
  3771. if (!add || !isObject(add)) return origin;
  3772. var keys = Object.keys(add);
  3773. var i = keys.length;
  3774. while (i--) {
  3775. origin[keys[i]] = add[keys[i]];
  3776. }
  3777. return origin;
  3778. };
  3779. function hasOwnProperty(obj, prop) {
  3780. return Object.prototype.hasOwnProperty.call(obj, prop);
  3781. }
  3782. },{"./support/isBuffer":31,"__browserify_process":29,"inherits":28}],33:[function(require,module,exports){
  3783. exports = (module.exports = parse);
  3784. exports.parse = parse;
  3785. function parse(src, state, options) {
  3786. options = options || {};
  3787. state = state || exports.defaultState();
  3788. var start = options.start || 0;
  3789. var end = options.end || src.length;
  3790. var index = start;
  3791. while (index < end) {
  3792. if (state.roundDepth < 0 || state.curlyDepth < 0 || state.squareDepth < 0) {
  3793. throw new SyntaxError('Mismatched Bracket: ' + src[index - 1]);
  3794. }
  3795. exports.parseChar(src[index++], state);
  3796. }
  3797. return state;
  3798. }
  3799. exports.parseMax = parseMax;
  3800. function parseMax(src, options) {
  3801. options = options || {};
  3802. var start = options.start || 0;
  3803. var index = start;
  3804. var state = exports.defaultState();
  3805. while (state.roundDepth >= 0 && state.curlyDepth >= 0 && state.squareDepth >= 0) {
  3806. if (index >= src.length) {
  3807. throw new Error('The end of the string was reached with no closing bracket found.');
  3808. }
  3809. exports.parseChar(src[index++], state);
  3810. }
  3811. var end = index - 1;
  3812. return {
  3813. start: start,
  3814. end: end,
  3815. src: src.substring(start, end)
  3816. };
  3817. }
  3818. exports.parseUntil = parseUntil;
  3819. function parseUntil(src, delimiter, options) {
  3820. options = options || {};
  3821. var includeLineComment = options.includeLineComment || false;
  3822. var start = options.start || 0;
  3823. var index = start;
  3824. var state = exports.defaultState();
  3825. while (state.isString() || state.regexp || state.blockComment ||
  3826. (!includeLineComment && state.lineComment) || !startsWith(src, delimiter, index)) {
  3827. exports.parseChar(src[index++], state);
  3828. }
  3829. var end = index;
  3830. return {
  3831. start: start,
  3832. end: end,
  3833. src: src.substring(start, end)
  3834. };
  3835. }
  3836. exports.parseChar = parseChar;
  3837. function parseChar(character, state) {
  3838. if (character.length !== 1) throw new Error('Character must be a string of length 1');
  3839. state = state || exports.defaultState();
  3840. var wasComment = state.blockComment || state.lineComment;
  3841. var lastChar = state.history ? state.history[0] : '';
  3842. if (state.lineComment) {
  3843. if (character === '\n') {
  3844. state.lineComment = false;
  3845. }
  3846. } else if (state.blockComment) {
  3847. if (state.lastChar === '*' && character === '/') {
  3848. state.blockComment = false;
  3849. }
  3850. } else if (state.singleQuote) {
  3851. if (character === '\'' && !state.escaped) {
  3852. state.singleQuote = false;
  3853. } else if (character === '\\' && !state.escaped) {
  3854. state.escaped = true;
  3855. } else {
  3856. state.escaped = false;
  3857. }
  3858. } else if (state.doubleQuote) {
  3859. if (character === '"' && !state.escaped) {
  3860. state.doubleQuote = false;
  3861. } else if (character === '\\' && !state.escaped) {
  3862. state.escaped = true;
  3863. } else {
  3864. state.escaped = false;
  3865. }
  3866. } else if (state.regexp) {
  3867. if (character === '/' && !state.escaped) {
  3868. state.regexp = false;
  3869. } else if (character === '\\' && !state.escaped) {
  3870. state.escaped = true;
  3871. } else {
  3872. state.escaped = false;
  3873. }
  3874. } else if (lastChar === '/' && character === '/') {
  3875. state.history = state.history.substr(1);
  3876. state.lineComment = true;
  3877. } else if (lastChar === '/' && character === '*') {
  3878. state.history = state.history.substr(1);
  3879. state.blockComment = true;
  3880. } else if (character === '/' && isRegexp(state.history)) {
  3881. state.regexp = true;
  3882. } else if (character === '\'') {
  3883. state.singleQuote = true;
  3884. } else if (character === '"') {
  3885. state.doubleQuote = true;
  3886. } else if (character === '(') {
  3887. state.roundDepth++;
  3888. } else if (character === ')') {
  3889. state.roundDepth--;
  3890. } else if (character === '{') {
  3891. state.curlyDepth++;
  3892. } else if (character === '}') {
  3893. state.curlyDepth--;
  3894. } else if (character === '[') {
  3895. state.squareDepth++;
  3896. } else if (character === ']') {
  3897. state.squareDepth--;
  3898. }
  3899. if (!state.blockComment && !state.lineComment && !wasComment) state.history = character + state.history;
  3900. return state;
  3901. }
  3902. exports.defaultState = function () { return new State() };
  3903. function State() {
  3904. this.lineComment = false;
  3905. this.blockComment = false;
  3906. this.singleQuote = false;
  3907. this.doubleQuote = false;
  3908. this.regexp = false;
  3909. this.escaped = false;
  3910. this.roundDepth = 0;
  3911. this.curlyDepth = 0;
  3912. this.squareDepth = 0;
  3913. this.history = ''
  3914. }
  3915. State.prototype.isString = function () {
  3916. return this.singleQuote || this.doubleQuote;
  3917. }
  3918. State.prototype.isComment = function () {
  3919. return this.lineComment || this.blockComment;
  3920. }
  3921. State.prototype.isNesting = function () {
  3922. return this.isString() || this.isComment() || this.regexp || this.roundDepth > 0 || this.curlyDepth > 0 || this.squareDepth > 0
  3923. }
  3924. function startsWith(str, start, i) {
  3925. return str.substr(i || 0, start.length) === start;
  3926. }
  3927. exports.isPunctuator = isPunctuator
  3928. function isPunctuator(c) {
  3929. var code = c.charCodeAt(0)
  3930. switch (code) {
  3931. case 46: // . dot
  3932. case 40: // ( open bracket
  3933. case 41: // ) close bracket
  3934. case 59: // ; semicolon
  3935. case 44: // , comma
  3936. case 123: // { open curly brace
  3937. case 125: // } close curly brace
  3938. case 91: // [
  3939. case 93: // ]
  3940. case 58: // :
  3941. case 63: // ?
  3942. case 126: // ~
  3943. case 37: // %
  3944. case 38: // &
  3945. case 42: // *:
  3946. case 43: // +
  3947. case 45: // -
  3948. case 47: // /
  3949. case 60: // <
  3950. case 62: // >
  3951. case 94: // ^
  3952. case 124: // |
  3953. case 33: // !
  3954. case 61: // =
  3955. return true;
  3956. default:
  3957. return false;
  3958. }
  3959. }
  3960. exports.isKeyword = isKeyword
  3961. function isKeyword(id) {
  3962. return (id === 'if') || (id === 'in') || (id === 'do') || (id === 'var') || (id === 'for') || (id === 'new') ||
  3963. (id === 'try') || (id === 'let') || (id === 'this') || (id === 'else') || (id === 'case') ||
  3964. (id === 'void') || (id === 'with') || (id === 'enum') || (id === 'while') || (id === 'break') || (id === 'catch') ||
  3965. (id === 'throw') || (id === 'const') || (id === 'yield') || (id === 'class') || (id === 'super') ||
  3966. (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch') || (id === 'export') ||
  3967. (id === 'import') || (id === 'default') || (id === 'finally') || (id === 'extends') || (id === 'function') ||
  3968. (id === 'continue') || (id === 'debugger') || (id === 'package') || (id === 'private') || (id === 'interface') ||
  3969. (id === 'instanceof') || (id === 'implements') || (id === 'protected') || (id === 'public') || (id === 'static') ||
  3970. (id === 'yield') || (id === 'let');
  3971. }
  3972. function isRegexp(history) {
  3973. //could be start of regexp or divide sign
  3974. history = history.replace(/^\s*/, '');
  3975. //unless its an `if`, `while`, `for` or `with` it's a divide, so we assume it's a divide
  3976. if (history[0] === ')') return false;
  3977. //unless it's a function expression, it's a regexp, so we assume it's a regexp
  3978. if (history[0] === '}') return true;
  3979. //any punctuation means it's a regexp
  3980. if (isPunctuator(history[0])) return true;
  3981. //if the last thing was a keyword then it must be a regexp (e.g. `typeof /foo/`)
  3982. if (/^\w+\b/.test(history) && isKeyword(/^\w+\b/.exec(history)[0].split('').reverse().join(''))) return true;
  3983. return false;
  3984. }
  3985. },{}],34:[function(require,module,exports){
  3986. 'use strict'
  3987. var uglify = require('uglify-js')
  3988. var lastSRC = '(null)'
  3989. var lastRes = true
  3990. module.exports = isConstant
  3991. function isConstant(src) {
  3992. src = '(' + src + ')'
  3993. if (lastSRC === src) return lastRes
  3994. lastSRC = src
  3995. try {
  3996. return lastRes = (detect(src).length === 0)
  3997. } catch (ex) {
  3998. return lastRes = false
  3999. }
  4000. }
  4001. isConstant.isConstant = isConstant
  4002. isConstant.toConstant = toConstant
  4003. function toConstant(src) {
  4004. if (!isConstant(src)) throw new Error(JSON.stringify(src) + ' is not constant.')
  4005. return Function('return (' + src + ')')()
  4006. }
  4007. function detect(src) {
  4008. var ast = uglify.parse(src.toString())
  4009. ast.figure_out_scope()
  4010. var globals = ast.globals
  4011. .map(function (node, name) {
  4012. return name
  4013. })
  4014. return globals
  4015. }
  4016. },{"uglify-js":45}],35:[function(require,module,exports){
  4017. /*
  4018. * Copyright 2009-2011 Mozilla Foundation and contributors
  4019. * Licensed under the New BSD license. See LICENSE.txt or:
  4020. * http://opensource.org/licenses/BSD-3-Clause
  4021. */
  4022. exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator;
  4023. exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer;
  4024. exports.SourceNode = require('./source-map/source-node').SourceNode;
  4025. },{"./source-map/source-map-consumer":40,"./source-map/source-map-generator":41,"./source-map/source-node":42}],36:[function(require,module,exports){
  4026. /* -*- Mode: js; js-indent-level: 2; -*- */
  4027. /*
  4028. * Copyright 2011 Mozilla Foundation and contributors
  4029. * Licensed under the New BSD license. See LICENSE or:
  4030. * http://opensource.org/licenses/BSD-3-Clause
  4031. */
  4032. if (typeof define !== 'function') {
  4033. var define = require('amdefine')(module, require);
  4034. }
  4035. define(function (require, exports, module) {
  4036. var util = require('./util');
  4037. /**
  4038. * A data structure which is a combination of an array and a set. Adding a new
  4039. * member is O(1), testing for membership is O(1), and finding the index of an
  4040. * element is O(1). Removing elements from the set is not supported. Only
  4041. * strings are supported for membership.
  4042. */
  4043. function ArraySet() {
  4044. this._array = [];
  4045. this._set = {};
  4046. }
  4047. /**
  4048. * Static method for creating ArraySet instances from an existing array.
  4049. */
  4050. ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) {
  4051. var set = new ArraySet();
  4052. for (var i = 0, len = aArray.length; i < len; i++) {
  4053. set.add(aArray[i], aAllowDuplicates);
  4054. }
  4055. return set;
  4056. };
  4057. /**
  4058. * Add the given string to this set.
  4059. *
  4060. * @param String aStr
  4061. */
  4062. ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) {
  4063. var isDuplicate = this.has(aStr);
  4064. var idx = this._array.length;
  4065. if (!isDuplicate || aAllowDuplicates) {
  4066. this._array.push(aStr);
  4067. }
  4068. if (!isDuplicate) {
  4069. this._set[util.toSetString(aStr)] = idx;
  4070. }
  4071. };
  4072. /**
  4073. * Is the given string a member of this set?
  4074. *
  4075. * @param String aStr
  4076. */
  4077. ArraySet.prototype.has = function ArraySet_has(aStr) {
  4078. return Object.prototype.hasOwnProperty.call(this._set,
  4079. util.toSetString(aStr));
  4080. };
  4081. /**
  4082. * What is the index of the given string in the array?
  4083. *
  4084. * @param String aStr
  4085. */
  4086. ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
  4087. if (this.has(aStr)) {
  4088. return this._set[util.toSetString(aStr)];
  4089. }
  4090. throw new Error('"' + aStr + '" is not in the set.');
  4091. };
  4092. /**
  4093. * What is the element at the given index?
  4094. *
  4095. * @param Number aIdx
  4096. */
  4097. ArraySet.prototype.at = function ArraySet_at(aIdx) {
  4098. if (aIdx >= 0 && aIdx < this._array.length) {
  4099. return this._array[aIdx];
  4100. }
  4101. throw new Error('No element indexed by ' + aIdx);
  4102. };
  4103. /**
  4104. * Returns the array representation of this set (which has the proper indices
  4105. * indicated by indexOf). Note that this is a copy of the internal array used
  4106. * for storing the members so that no one can mess with internal state.
  4107. */
  4108. ArraySet.prototype.toArray = function ArraySet_toArray() {
  4109. return this._array.slice();
  4110. };
  4111. exports.ArraySet = ArraySet;
  4112. });
  4113. },{"./util":43,"amdefine":44}],37:[function(require,module,exports){
  4114. /* -*- Mode: js; js-indent-level: 2; -*- */
  4115. /*
  4116. * Copyright 2011 Mozilla Foundation and contributors
  4117. * Licensed under the New BSD license. See LICENSE or:
  4118. * http://opensource.org/licenses/BSD-3-Clause
  4119. *
  4120. * Based on the Base 64 VLQ implementation in Closure Compiler:
  4121. * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
  4122. *
  4123. * Copyright 2011 The Closure Compiler Authors. All rights reserved.
  4124. * Redistribution and use in source and binary forms, with or without
  4125. * modification, are permitted provided that the following conditions are
  4126. * met:
  4127. *
  4128. * * Redistributions of source code must retain the above copyright
  4129. * notice, this list of conditions and the following disclaimer.
  4130. * * Redistributions in binary form must reproduce the above
  4131. * copyright notice, this list of conditions and the following
  4132. * disclaimer in the documentation and/or other materials provided
  4133. * with the distribution.
  4134. * * Neither the name of Google Inc. nor the names of its
  4135. * contributors may be used to endorse or promote products derived
  4136. * from this software without specific prior written permission.
  4137. *
  4138. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4139. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  4140. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  4141. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  4142. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  4143. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  4144. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  4145. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  4146. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  4147. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  4148. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  4149. */
  4150. if (typeof define !== 'function') {
  4151. var define = require('amdefine')(module, require);
  4152. }
  4153. define(function (require, exports, module) {
  4154. var base64 = require('./base64');
  4155. // A single base 64 digit can contain 6 bits of data. For the base 64 variable
  4156. // length quantities we use in the source map spec, the first bit is the sign,
  4157. // the next four bits are the actual value, and the 6th bit is the
  4158. // continuation bit. The continuation bit tells us whether there are more
  4159. // digits in this value following this digit.
  4160. //
  4161. // Continuation
  4162. // | Sign
  4163. // | |
  4164. // V V
  4165. // 101011
  4166. var VLQ_BASE_SHIFT = 5;
  4167. // binary: 100000
  4168. var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
  4169. // binary: 011111
  4170. var VLQ_BASE_MASK = VLQ_BASE - 1;
  4171. // binary: 100000
  4172. var VLQ_CONTINUATION_BIT = VLQ_BASE;
  4173. /**
  4174. * Converts from a two-complement value to a value where the sign bit is
  4175. * is placed in the least significant bit. For example, as decimals:
  4176. * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
  4177. * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
  4178. */
  4179. function toVLQSigned(aValue) {
  4180. return aValue < 0
  4181. ? ((-aValue) << 1) + 1
  4182. : (aValue << 1) + 0;
  4183. }
  4184. /**
  4185. * Converts to a two-complement value from a value where the sign bit is
  4186. * is placed in the least significant bit. For example, as decimals:
  4187. * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
  4188. * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
  4189. */
  4190. function fromVLQSigned(aValue) {
  4191. var isNegative = (aValue & 1) === 1;
  4192. var shifted = aValue >> 1;
  4193. return isNegative
  4194. ? -shifted
  4195. : shifted;
  4196. }
  4197. /**
  4198. * Returns the base 64 VLQ encoded value.
  4199. */
  4200. exports.encode = function base64VLQ_encode(aValue) {
  4201. var encoded = "";
  4202. var digit;
  4203. var vlq = toVLQSigned(aValue);
  4204. do {
  4205. digit = vlq & VLQ_BASE_MASK;
  4206. vlq >>>= VLQ_BASE_SHIFT;
  4207. if (vlq > 0) {
  4208. // There are still more digits in this value, so we must make sure the
  4209. // continuation bit is marked.
  4210. digit |= VLQ_CONTINUATION_BIT;
  4211. }
  4212. encoded += base64.encode(digit);
  4213. } while (vlq > 0);
  4214. return encoded;
  4215. };
  4216. /**
  4217. * Decodes the next base 64 VLQ value from the given string and returns the
  4218. * value and the rest of the string.
  4219. */
  4220. exports.decode = function base64VLQ_decode(aStr) {
  4221. var i = 0;
  4222. var strLen = aStr.length;
  4223. var result = 0;
  4224. var shift = 0;
  4225. var continuation, digit;
  4226. do {
  4227. if (i >= strLen) {
  4228. throw new Error("Expected more digits in base 64 VLQ value.");
  4229. }
  4230. digit = base64.decode(aStr.charAt(i++));
  4231. continuation = !!(digit & VLQ_CONTINUATION_BIT);
  4232. digit &= VLQ_BASE_MASK;
  4233. result = result + (digit << shift);
  4234. shift += VLQ_BASE_SHIFT;
  4235. } while (continuation);
  4236. return {
  4237. value: fromVLQSigned(result),
  4238. rest: aStr.slice(i)
  4239. };
  4240. };
  4241. });
  4242. },{"./base64":38,"amdefine":44}],38:[function(require,module,exports){
  4243. /* -*- Mode: js; js-indent-level: 2; -*- */
  4244. /*
  4245. * Copyright 2011 Mozilla Foundation and contributors
  4246. * Licensed under the New BSD license. See LICENSE or:
  4247. * http://opensource.org/licenses/BSD-3-Clause
  4248. */
  4249. if (typeof define !== 'function') {
  4250. var define = require('amdefine')(module, require);
  4251. }
  4252. define(function (require, exports, module) {
  4253. var charToIntMap = {};
  4254. var intToCharMap = {};
  4255. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  4256. .split('')
  4257. .forEach(function (ch, index) {
  4258. charToIntMap[ch] = index;
  4259. intToCharMap[index] = ch;
  4260. });
  4261. /**
  4262. * Encode an integer in the range of 0 to 63 to a single base 64 digit.
  4263. */
  4264. exports.encode = function base64_encode(aNumber) {
  4265. if (aNumber in intToCharMap) {
  4266. return intToCharMap[aNumber];
  4267. }
  4268. throw new TypeError("Must be between 0 and 63: " + aNumber);
  4269. };
  4270. /**
  4271. * Decode a single base 64 digit to an integer.
  4272. */
  4273. exports.decode = function base64_decode(aChar) {
  4274. if (aChar in charToIntMap) {
  4275. return charToIntMap[aChar];
  4276. }
  4277. throw new TypeError("Not a valid base 64 digit: " + aChar);
  4278. };
  4279. });
  4280. },{"amdefine":44}],39:[function(require,module,exports){
  4281. /* -*- Mode: js; js-indent-level: 2; -*- */
  4282. /*
  4283. * Copyright 2011 Mozilla Foundation and contributors
  4284. * Licensed under the New BSD license. See LICENSE or:
  4285. * http://opensource.org/licenses/BSD-3-Clause
  4286. */
  4287. if (typeof define !== 'function') {
  4288. var define = require('amdefine')(module, require);
  4289. }
  4290. define(function (require, exports, module) {
  4291. /**
  4292. * Recursive implementation of binary search.
  4293. *
  4294. * @param aLow Indices here and lower do not contain the needle.
  4295. * @param aHigh Indices here and higher do not contain the needle.
  4296. * @param aNeedle The element being searched for.
  4297. * @param aHaystack The non-empty array being searched.
  4298. * @param aCompare Function which takes two elements and returns -1, 0, or 1.
  4299. */
  4300. function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) {
  4301. // This function terminates when one of the following is true:
  4302. //
  4303. // 1. We find the exact element we are looking for.
  4304. //
  4305. // 2. We did not find the exact element, but we can return the next
  4306. // closest element that is less than that element.
  4307. //
  4308. // 3. We did not find the exact element, and there is no next-closest
  4309. // element which is less than the one we are searching for, so we
  4310. // return null.
  4311. var mid = Math.floor((aHigh - aLow) / 2) + aLow;
  4312. var cmp = aCompare(aNeedle, aHaystack[mid], true);
  4313. if (cmp === 0) {
  4314. // Found the element we are looking for.
  4315. return aHaystack[mid];
  4316. }
  4317. else if (cmp > 0) {
  4318. // aHaystack[mid] is greater than our needle.
  4319. if (aHigh - mid > 1) {
  4320. // The element is in the upper half.
  4321. return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare);
  4322. }
  4323. // We did not find an exact match, return the next closest one
  4324. // (termination case 2).
  4325. return aHaystack[mid];
  4326. }
  4327. else {
  4328. // aHaystack[mid] is less than our needle.
  4329. if (mid - aLow > 1) {
  4330. // The element is in the lower half.
  4331. return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare);
  4332. }
  4333. // The exact needle element was not found in this haystack. Determine if
  4334. // we are in termination case (2) or (3) and return the appropriate thing.
  4335. return aLow < 0
  4336. ? null
  4337. : aHaystack[aLow];
  4338. }
  4339. }
  4340. /**
  4341. * This is an implementation of binary search which will always try and return
  4342. * the next lowest value checked if there is no exact hit. This is because
  4343. * mappings between original and generated line/col pairs are single points,
  4344. * and there is an implicit region between each of them, so a miss just means
  4345. * that you aren't on the very start of a region.
  4346. *
  4347. * @param aNeedle The element you are looking for.
  4348. * @param aHaystack The array that is being searched.
  4349. * @param aCompare A function which takes the needle and an element in the
  4350. * array and returns -1, 0, or 1 depending on whether the needle is less
  4351. * than, equal to, or greater than the element, respectively.
  4352. */
  4353. exports.search = function search(aNeedle, aHaystack, aCompare) {
  4354. return aHaystack.length > 0
  4355. ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
  4356. : null;
  4357. };
  4358. });
  4359. },{"amdefine":44}],40:[function(require,module,exports){
  4360. /* -*- Mode: js; js-indent-level: 2; -*- */
  4361. /*
  4362. * Copyright 2011 Mozilla Foundation and contributors
  4363. * Licensed under the New BSD license. See LICENSE or:
  4364. * http://opensource.org/licenses/BSD-3-Clause
  4365. */
  4366. if (typeof define !== 'function') {
  4367. var define = require('amdefine')(module, require);
  4368. }
  4369. define(function (require, exports, module) {
  4370. var util = require('./util');
  4371. var binarySearch = require('./binary-search');
  4372. var ArraySet = require('./array-set').ArraySet;
  4373. var base64VLQ = require('./base64-vlq');
  4374. /**
  4375. * A SourceMapConsumer instance represents a parsed source map which we can
  4376. * query for information about the original file positions by giving it a file
  4377. * position in the generated source.
  4378. *
  4379. * The only parameter is the raw source map (either as a JSON string, or
  4380. * already parsed to an object). According to the spec, source maps have the
  4381. * following attributes:
  4382. *
  4383. * - version: Which version of the source map spec this map is following.
  4384. * - sources: An array of URLs to the original source files.
  4385. * - names: An array of identifiers which can be referrenced by individual mappings.
  4386. * - sourceRoot: Optional. The URL root from which all sources are relative.
  4387. * - sourcesContent: Optional. An array of contents of the original source files.
  4388. * - mappings: A string of base64 VLQs which contain the actual mappings.
  4389. * - file: The generated file this source map is associated with.
  4390. *
  4391. * Here is an example source map, taken from the source map spec[0]:
  4392. *
  4393. * {
  4394. * version : 3,
  4395. * file: "out.js",
  4396. * sourceRoot : "",
  4397. * sources: ["foo.js", "bar.js"],
  4398. * names: ["src", "maps", "are", "fun"],
  4399. * mappings: "AA,AB;;ABCDE;"
  4400. * }
  4401. *
  4402. * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
  4403. */
  4404. function SourceMapConsumer(aSourceMap) {
  4405. var sourceMap = aSourceMap;
  4406. if (typeof aSourceMap === 'string') {
  4407. sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
  4408. }
  4409. var version = util.getArg(sourceMap, 'version');
  4410. var sources = util.getArg(sourceMap, 'sources');
  4411. // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
  4412. // requires the array) to play nice here.
  4413. var names = util.getArg(sourceMap, 'names', []);
  4414. var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
  4415. var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
  4416. var mappings = util.getArg(sourceMap, 'mappings');
  4417. var file = util.getArg(sourceMap, 'file', null);
  4418. // Once again, Sass deviates from the spec and supplies the version as a
  4419. // string rather than a number, so we use loose equality checking here.
  4420. if (version != this._version) {
  4421. throw new Error('Unsupported version: ' + version);
  4422. }
  4423. // Pass `true` below to allow duplicate names and sources. While source maps
  4424. // are intended to be compressed and deduplicated, the TypeScript compiler
  4425. // sometimes generates source maps with duplicates in them. See Github issue
  4426. // #72 and bugzil.la/889492.
  4427. this._names = ArraySet.fromArray(names, true);
  4428. this._sources = ArraySet.fromArray(sources, true);
  4429. this.sourceRoot = sourceRoot;
  4430. this.sourcesContent = sourcesContent;
  4431. this._mappings = mappings;
  4432. this.file = file;
  4433. }
  4434. /**
  4435. * Create a SourceMapConsumer from a SourceMapGenerator.
  4436. *
  4437. * @param SourceMapGenerator aSourceMap
  4438. * The source map that will be consumed.
  4439. * @returns SourceMapConsumer
  4440. */
  4441. SourceMapConsumer.fromSourceMap =
  4442. function SourceMapConsumer_fromSourceMap(aSourceMap) {
  4443. var smc = Object.create(SourceMapConsumer.prototype);
  4444. smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
  4445. smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
  4446. smc.sourceRoot = aSourceMap._sourceRoot;
  4447. smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
  4448. smc.sourceRoot);
  4449. smc.file = aSourceMap._file;
  4450. smc.__generatedMappings = aSourceMap._mappings.slice()
  4451. .sort(util.compareByGeneratedPositions);
  4452. smc.__originalMappings = aSourceMap._mappings.slice()
  4453. .sort(util.compareByOriginalPositions);
  4454. return smc;
  4455. };
  4456. /**
  4457. * The version of the source mapping spec that we are consuming.
  4458. */
  4459. SourceMapConsumer.prototype._version = 3;
  4460. /**
  4461. * The list of original sources.
  4462. */
  4463. Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
  4464. get: function () {
  4465. return this._sources.toArray().map(function (s) {
  4466. return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
  4467. }, this);
  4468. }
  4469. });
  4470. // `__generatedMappings` and `__originalMappings` are arrays that hold the
  4471. // parsed mapping coordinates from the source map's "mappings" attribute. They
  4472. // are lazily instantiated, accessed via the `_generatedMappings` and
  4473. // `_originalMappings` getters respectively, and we only parse the mappings
  4474. // and create these arrays once queried for a source location. We jump through
  4475. // these hoops because there can be many thousands of mappings, and parsing
  4476. // them is expensive, so we only want to do it if we must.
  4477. //
  4478. // Each object in the arrays is of the form:
  4479. //
  4480. // {
  4481. // generatedLine: The line number in the generated code,
  4482. // generatedColumn: The column number in the generated code,
  4483. // source: The path to the original source file that generated this
  4484. // chunk of code,
  4485. // originalLine: The line number in the original source that
  4486. // corresponds to this chunk of generated code,
  4487. // originalColumn: The column number in the original source that
  4488. // corresponds to this chunk of generated code,
  4489. // name: The name of the original symbol which generated this chunk of
  4490. // code.
  4491. // }
  4492. //
  4493. // All properties except for `generatedLine` and `generatedColumn` can be
  4494. // `null`.
  4495. //
  4496. // `_generatedMappings` is ordered by the generated positions.
  4497. //
  4498. // `_originalMappings` is ordered by the original positions.
  4499. SourceMapConsumer.prototype.__generatedMappings = null;
  4500. Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
  4501. get: function () {
  4502. if (!this.__generatedMappings) {
  4503. this.__generatedMappings = [];
  4504. this.__originalMappings = [];
  4505. this._parseMappings(this._mappings, this.sourceRoot);
  4506. }
  4507. return this.__generatedMappings;
  4508. }
  4509. });
  4510. SourceMapConsumer.prototype.__originalMappings = null;
  4511. Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
  4512. get: function () {
  4513. if (!this.__originalMappings) {
  4514. this.__generatedMappings = [];
  4515. this.__originalMappings = [];
  4516. this._parseMappings(this._mappings, this.sourceRoot);
  4517. }
  4518. return this.__originalMappings;
  4519. }
  4520. });
  4521. /**
  4522. * Parse the mappings in a string in to a data structure which we can easily
  4523. * query (the ordered arrays in the `this.__generatedMappings` and
  4524. * `this.__originalMappings` properties).
  4525. */
  4526. SourceMapConsumer.prototype._parseMappings =
  4527. function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
  4528. var generatedLine = 1;
  4529. var previousGeneratedColumn = 0;
  4530. var previousOriginalLine = 0;
  4531. var previousOriginalColumn = 0;
  4532. var previousSource = 0;
  4533. var previousName = 0;
  4534. var mappingSeparator = /^[,;]/;
  4535. var str = aStr;
  4536. var mapping;
  4537. var temp;
  4538. while (str.length > 0) {
  4539. if (str.charAt(0) === ';') {
  4540. generatedLine++;
  4541. str = str.slice(1);
  4542. previousGeneratedColumn = 0;
  4543. }
  4544. else if (str.charAt(0) === ',') {
  4545. str = str.slice(1);
  4546. }
  4547. else {
  4548. mapping = {};
  4549. mapping.generatedLine = generatedLine;
  4550. // Generated column.
  4551. temp = base64VLQ.decode(str);
  4552. mapping.generatedColumn = previousGeneratedColumn + temp.value;
  4553. previousGeneratedColumn = mapping.generatedColumn;
  4554. str = temp.rest;
  4555. if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
  4556. // Original source.
  4557. temp = base64VLQ.decode(str);
  4558. mapping.source = this._sources.at(previousSource + temp.value);
  4559. previousSource += temp.value;
  4560. str = temp.rest;
  4561. if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
  4562. throw new Error('Found a source, but no line and column');
  4563. }
  4564. // Original line.
  4565. temp = base64VLQ.decode(str);
  4566. mapping.originalLine = previousOriginalLine + temp.value;
  4567. previousOriginalLine = mapping.originalLine;
  4568. // Lines are stored 0-based
  4569. mapping.originalLine += 1;
  4570. str = temp.rest;
  4571. if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
  4572. throw new Error('Found a source and line, but no column');
  4573. }
  4574. // Original column.
  4575. temp = base64VLQ.decode(str);
  4576. mapping.originalColumn = previousOriginalColumn + temp.value;
  4577. previousOriginalColumn = mapping.originalColumn;
  4578. str = temp.rest;
  4579. if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
  4580. // Original name.
  4581. temp = base64VLQ.decode(str);
  4582. mapping.name = this._names.at(previousName + temp.value);
  4583. previousName += temp.value;
  4584. str = temp.rest;
  4585. }
  4586. }
  4587. this.__generatedMappings.push(mapping);
  4588. if (typeof mapping.originalLine === 'number') {
  4589. this.__originalMappings.push(mapping);
  4590. }
  4591. }
  4592. }
  4593. this.__originalMappings.sort(util.compareByOriginalPositions);
  4594. };
  4595. /**
  4596. * Find the mapping that best matches the hypothetical "needle" mapping that
  4597. * we are searching for in the given "haystack" of mappings.
  4598. */
  4599. SourceMapConsumer.prototype._findMapping =
  4600. function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
  4601. aColumnName, aComparator) {
  4602. // To return the position we are searching for, we must first find the
  4603. // mapping for the given position and then return the opposite position it
  4604. // points to. Because the mappings are sorted, we can use binary search to
  4605. // find the best mapping.
  4606. if (aNeedle[aLineName] <= 0) {
  4607. throw new TypeError('Line must be greater than or equal to 1, got '
  4608. + aNeedle[aLineName]);
  4609. }
  4610. if (aNeedle[aColumnName] < 0) {
  4611. throw new TypeError('Column must be greater than or equal to 0, got '
  4612. + aNeedle[aColumnName]);
  4613. }
  4614. return binarySearch.search(aNeedle, aMappings, aComparator);
  4615. };
  4616. /**
  4617. * Returns the original source, line, and column information for the generated
  4618. * source's line and column positions provided. The only argument is an object
  4619. * with the following properties:
  4620. *
  4621. * - line: The line number in the generated source.
  4622. * - column: The column number in the generated source.
  4623. *
  4624. * and an object is returned with the following properties:
  4625. *
  4626. * - source: The original source file, or null.
  4627. * - line: The line number in the original source, or null.
  4628. * - column: The column number in the original source, or null.
  4629. * - name: The original identifier, or null.
  4630. */
  4631. SourceMapConsumer.prototype.originalPositionFor =
  4632. function SourceMapConsumer_originalPositionFor(aArgs) {
  4633. var needle = {
  4634. generatedLine: util.getArg(aArgs, 'line'),
  4635. generatedColumn: util.getArg(aArgs, 'column')
  4636. };
  4637. var mapping = this._findMapping(needle,
  4638. this._generatedMappings,
  4639. "generatedLine",
  4640. "generatedColumn",
  4641. util.compareByGeneratedPositions);
  4642. if (mapping) {
  4643. var source = util.getArg(mapping, 'source', null);
  4644. if (source && this.sourceRoot) {
  4645. source = util.join(this.sourceRoot, source);
  4646. }
  4647. return {
  4648. source: source,
  4649. line: util.getArg(mapping, 'originalLine', null),
  4650. column: util.getArg(mapping, 'originalColumn', null),
  4651. name: util.getArg(mapping, 'name', null)
  4652. };
  4653. }
  4654. return {
  4655. source: null,
  4656. line: null,
  4657. column: null,
  4658. name: null
  4659. };
  4660. };
  4661. /**
  4662. * Returns the original source content. The only argument is the url of the
  4663. * original source file. Returns null if no original source content is
  4664. * availible.
  4665. */
  4666. SourceMapConsumer.prototype.sourceContentFor =
  4667. function SourceMapConsumer_sourceContentFor(aSource) {
  4668. if (!this.sourcesContent) {
  4669. return null;
  4670. }
  4671. if (this.sourceRoot) {
  4672. aSource = util.relative(this.sourceRoot, aSource);
  4673. }
  4674. if (this._sources.has(aSource)) {
  4675. return this.sourcesContent[this._sources.indexOf(aSource)];
  4676. }
  4677. var url;
  4678. if (this.sourceRoot
  4679. && (url = util.urlParse(this.sourceRoot))) {
  4680. // XXX: file:// URIs and absolute paths lead to unexpected behavior for
  4681. // many users. We can help them out when they expect file:// URIs to
  4682. // behave like it would if they were running a local HTTP server. See
  4683. // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
  4684. var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
  4685. if (url.scheme == "file"
  4686. && this._sources.has(fileUriAbsPath)) {
  4687. return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
  4688. }
  4689. if ((!url.path || url.path == "/")
  4690. && this._sources.has("/" + aSource)) {
  4691. return this.sourcesContent[this._sources.indexOf("/" + aSource)];
  4692. }
  4693. }
  4694. throw new Error('"' + aSource + '" is not in the SourceMap.');
  4695. };
  4696. /**
  4697. * Returns the generated line and column information for the original source,
  4698. * line, and column positions provided. The only argument is an object with
  4699. * the following properties:
  4700. *
  4701. * - source: The filename of the original source.
  4702. * - line: The line number in the original source.
  4703. * - column: The column number in the original source.
  4704. *
  4705. * and an object is returned with the following properties:
  4706. *
  4707. * - line: The line number in the generated source, or null.
  4708. * - column: The column number in the generated source, or null.
  4709. */
  4710. SourceMapConsumer.prototype.generatedPositionFor =
  4711. function SourceMapConsumer_generatedPositionFor(aArgs) {
  4712. var needle = {
  4713. source: util.getArg(aArgs, 'source'),
  4714. originalLine: util.getArg(aArgs, 'line'),
  4715. originalColumn: util.getArg(aArgs, 'column')
  4716. };
  4717. if (this.sourceRoot) {
  4718. needle.source = util.relative(this.sourceRoot, needle.source);
  4719. }
  4720. var mapping = this._findMapping(needle,
  4721. this._originalMappings,
  4722. "originalLine",
  4723. "originalColumn",
  4724. util.compareByOriginalPositions);
  4725. if (mapping) {
  4726. return {
  4727. line: util.getArg(mapping, 'generatedLine', null),
  4728. column: util.getArg(mapping, 'generatedColumn', null)
  4729. };
  4730. }
  4731. return {
  4732. line: null,
  4733. column: null
  4734. };
  4735. };
  4736. SourceMapConsumer.GENERATED_ORDER = 1;
  4737. SourceMapConsumer.ORIGINAL_ORDER = 2;
  4738. /**
  4739. * Iterate over each mapping between an original source/line/column and a
  4740. * generated line/column in this source map.
  4741. *
  4742. * @param Function aCallback
  4743. * The function that is called with each mapping.
  4744. * @param Object aContext
  4745. * Optional. If specified, this object will be the value of `this` every
  4746. * time that `aCallback` is called.
  4747. * @param aOrder
  4748. * Either `SourceMapConsumer.GENERATED_ORDER` or
  4749. * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
  4750. * iterate over the mappings sorted by the generated file's line/column
  4751. * order or the original's source/line/column order, respectively. Defaults to
  4752. * `SourceMapConsumer.GENERATED_ORDER`.
  4753. */
  4754. SourceMapConsumer.prototype.eachMapping =
  4755. function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
  4756. var context = aContext || null;
  4757. var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
  4758. var mappings;
  4759. switch (order) {
  4760. case SourceMapConsumer.GENERATED_ORDER:
  4761. mappings = this._generatedMappings;
  4762. break;
  4763. case SourceMapConsumer.ORIGINAL_ORDER:
  4764. mappings = this._originalMappings;
  4765. break;
  4766. default:
  4767. throw new Error("Unknown order of iteration.");
  4768. }
  4769. var sourceRoot = this.sourceRoot;
  4770. mappings.map(function (mapping) {
  4771. var source = mapping.source;
  4772. if (source && sourceRoot) {
  4773. source = util.join(sourceRoot, source);
  4774. }
  4775. return {
  4776. source: source,
  4777. generatedLine: mapping.generatedLine,
  4778. generatedColumn: mapping.generatedColumn,
  4779. originalLine: mapping.originalLine,
  4780. originalColumn: mapping.originalColumn,
  4781. name: mapping.name
  4782. };
  4783. }).forEach(aCallback, context);
  4784. };
  4785. exports.SourceMapConsumer = SourceMapConsumer;
  4786. });
  4787. },{"./array-set":36,"./base64-vlq":37,"./binary-search":39,"./util":43,"amdefine":44}],41:[function(require,module,exports){
  4788. /* -*- Mode: js; js-indent-level: 2; -*- */
  4789. /*
  4790. * Copyright 2011 Mozilla Foundation and contributors
  4791. * Licensed under the New BSD license. See LICENSE or:
  4792. * http://opensource.org/licenses/BSD-3-Clause
  4793. */
  4794. if (typeof define !== 'function') {
  4795. var define = require('amdefine')(module, require);
  4796. }
  4797. define(function (require, exports, module) {
  4798. var base64VLQ = require('./base64-vlq');
  4799. var util = require('./util');
  4800. var ArraySet = require('./array-set').ArraySet;
  4801. /**
  4802. * An instance of the SourceMapGenerator represents a source map which is
  4803. * being built incrementally. To create a new one, you must pass an object
  4804. * with the following properties:
  4805. *
  4806. * - file: The filename of the generated source.
  4807. * - sourceRoot: An optional root for all URLs in this source map.
  4808. */
  4809. function SourceMapGenerator(aArgs) {
  4810. this._file = util.getArg(aArgs, 'file');
  4811. this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
  4812. this._sources = new ArraySet();
  4813. this._names = new ArraySet();
  4814. this._mappings = [];
  4815. this._sourcesContents = null;
  4816. }
  4817. SourceMapGenerator.prototype._version = 3;
  4818. /**
  4819. * Creates a new SourceMapGenerator based on a SourceMapConsumer
  4820. *
  4821. * @param aSourceMapConsumer The SourceMap.
  4822. */
  4823. SourceMapGenerator.fromSourceMap =
  4824. function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
  4825. var sourceRoot = aSourceMapConsumer.sourceRoot;
  4826. var generator = new SourceMapGenerator({
  4827. file: aSourceMapConsumer.file,
  4828. sourceRoot: sourceRoot
  4829. });
  4830. aSourceMapConsumer.eachMapping(function (mapping) {
  4831. var newMapping = {
  4832. generated: {
  4833. line: mapping.generatedLine,
  4834. column: mapping.generatedColumn
  4835. }
  4836. };
  4837. if (mapping.source) {
  4838. newMapping.source = mapping.source;
  4839. if (sourceRoot) {
  4840. newMapping.source = util.relative(sourceRoot, newMapping.source);
  4841. }
  4842. newMapping.original = {
  4843. line: mapping.originalLine,
  4844. column: mapping.originalColumn
  4845. };
  4846. if (mapping.name) {
  4847. newMapping.name = mapping.name;
  4848. }
  4849. }
  4850. generator.addMapping(newMapping);
  4851. });
  4852. aSourceMapConsumer.sources.forEach(function (sourceFile) {
  4853. var content = aSourceMapConsumer.sourceContentFor(sourceFile);
  4854. if (content) {
  4855. generator.setSourceContent(sourceFile, content);
  4856. }
  4857. });
  4858. return generator;
  4859. };
  4860. /**
  4861. * Add a single mapping from original source line and column to the generated
  4862. * source's line and column for this source map being created. The mapping
  4863. * object should have the following properties:
  4864. *
  4865. * - generated: An object with the generated line and column positions.
  4866. * - original: An object with the original line and column positions.
  4867. * - source: The original source file (relative to the sourceRoot).
  4868. * - name: An optional original token name for this mapping.
  4869. */
  4870. SourceMapGenerator.prototype.addMapping =
  4871. function SourceMapGenerator_addMapping(aArgs) {
  4872. var generated = util.getArg(aArgs, 'generated');
  4873. var original = util.getArg(aArgs, 'original', null);
  4874. var source = util.getArg(aArgs, 'source', null);
  4875. var name = util.getArg(aArgs, 'name', null);
  4876. this._validateMapping(generated, original, source, name);
  4877. if (source && !this._sources.has(source)) {
  4878. this._sources.add(source);
  4879. }
  4880. if (name && !this._names.has(name)) {
  4881. this._names.add(name);
  4882. }
  4883. this._mappings.push({
  4884. generatedLine: generated.line,
  4885. generatedColumn: generated.column,
  4886. originalLine: original != null && original.line,
  4887. originalColumn: original != null && original.column,
  4888. source: source,
  4889. name: name
  4890. });
  4891. };
  4892. /**
  4893. * Set the source content for a source file.
  4894. */
  4895. SourceMapGenerator.prototype.setSourceContent =
  4896. function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
  4897. var source = aSourceFile;
  4898. if (this._sourceRoot) {
  4899. source = util.relative(this._sourceRoot, source);
  4900. }
  4901. if (aSourceContent !== null) {
  4902. // Add the source content to the _sourcesContents map.
  4903. // Create a new _sourcesContents map if the property is null.
  4904. if (!this._sourcesContents) {
  4905. this._sourcesContents = {};
  4906. }
  4907. this._sourcesContents[util.toSetString(source)] = aSourceContent;
  4908. } else {
  4909. // Remove the source file from the _sourcesContents map.
  4910. // If the _sourcesContents map is empty, set the property to null.
  4911. delete this._sourcesContents[util.toSetString(source)];
  4912. if (Object.keys(this._sourcesContents).length === 0) {
  4913. this._sourcesContents = null;
  4914. }
  4915. }
  4916. };
  4917. /**
  4918. * Applies the mappings of a sub-source-map for a specific source file to the
  4919. * source map being generated. Each mapping to the supplied source file is
  4920. * rewritten using the supplied source map. Note: The resolution for the
  4921. * resulting mappings is the minimium of this map and the supplied map.
  4922. *
  4923. * @param aSourceMapConsumer The source map to be applied.
  4924. * @param aSourceFile Optional. The filename of the source file.
  4925. * If omitted, SourceMapConsumer's file property will be used.
  4926. */
  4927. SourceMapGenerator.prototype.applySourceMap =
  4928. function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) {
  4929. // If aSourceFile is omitted, we will use the file property of the SourceMap
  4930. if (!aSourceFile) {
  4931. aSourceFile = aSourceMapConsumer.file;
  4932. }
  4933. var sourceRoot = this._sourceRoot;
  4934. // Make "aSourceFile" relative if an absolute Url is passed.
  4935. if (sourceRoot) {
  4936. aSourceFile = util.relative(sourceRoot, aSourceFile);
  4937. }
  4938. // Applying the SourceMap can add and remove items from the sources and
  4939. // the names array.
  4940. var newSources = new ArraySet();
  4941. var newNames = new ArraySet();
  4942. // Find mappings for the "aSourceFile"
  4943. this._mappings.forEach(function (mapping) {
  4944. if (mapping.source === aSourceFile && mapping.originalLine) {
  4945. // Check if it can be mapped by the source map, then update the mapping.
  4946. var original = aSourceMapConsumer.originalPositionFor({
  4947. line: mapping.originalLine,
  4948. column: mapping.originalColumn
  4949. });
  4950. if (original.source !== null) {
  4951. // Copy mapping
  4952. if (sourceRoot) {
  4953. mapping.source = util.relative(sourceRoot, original.source);
  4954. } else {
  4955. mapping.source = original.source;
  4956. }
  4957. mapping.originalLine = original.line;
  4958. mapping.originalColumn = original.column;
  4959. if (original.name !== null && mapping.name !== null) {
  4960. // Only use the identifier name if it's an identifier
  4961. // in both SourceMaps
  4962. mapping.name = original.name;
  4963. }
  4964. }
  4965. }
  4966. var source = mapping.source;
  4967. if (source && !newSources.has(source)) {
  4968. newSources.add(source);
  4969. }
  4970. var name = mapping.name;
  4971. if (name && !newNames.has(name)) {
  4972. newNames.add(name);
  4973. }
  4974. }, this);
  4975. this._sources = newSources;
  4976. this._names = newNames;
  4977. // Copy sourcesContents of applied map.
  4978. aSourceMapConsumer.sources.forEach(function (sourceFile) {
  4979. var content = aSourceMapConsumer.sourceContentFor(sourceFile);
  4980. if (content) {
  4981. if (sourceRoot) {
  4982. sourceFile = util.relative(sourceRoot, sourceFile);
  4983. }
  4984. this.setSourceContent(sourceFile, content);
  4985. }
  4986. }, this);
  4987. };
  4988. /**
  4989. * A mapping can have one of the three levels of data:
  4990. *
  4991. * 1. Just the generated position.
  4992. * 2. The Generated position, original position, and original source.
  4993. * 3. Generated and original position, original source, as well as a name
  4994. * token.
  4995. *
  4996. * To maintain consistency, we validate that any new mapping being added falls
  4997. * in to one of these categories.
  4998. */
  4999. SourceMapGenerator.prototype._validateMapping =
  5000. function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
  5001. aName) {
  5002. if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
  5003. && aGenerated.line > 0 && aGenerated.column >= 0
  5004. && !aOriginal && !aSource && !aName) {
  5005. // Case 1.
  5006. return;
  5007. }
  5008. else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
  5009. && aOriginal && 'line' in aOriginal && 'column' in aOriginal
  5010. && aGenerated.line > 0 && aGenerated.column >= 0
  5011. && aOriginal.line > 0 && aOriginal.column >= 0
  5012. && aSource) {
  5013. // Cases 2 and 3.
  5014. return;
  5015. }
  5016. else {
  5017. throw new Error('Invalid mapping: ' + JSON.stringify({
  5018. generated: aGenerated,
  5019. source: aSource,
  5020. orginal: aOriginal,
  5021. name: aName
  5022. }));
  5023. }
  5024. };
  5025. /**
  5026. * Serialize the accumulated mappings in to the stream of base 64 VLQs
  5027. * specified by the source map format.
  5028. */
  5029. SourceMapGenerator.prototype._serializeMappings =
  5030. function SourceMapGenerator_serializeMappings() {
  5031. var previousGeneratedColumn = 0;
  5032. var previousGeneratedLine = 1;
  5033. var previousOriginalColumn = 0;
  5034. var previousOriginalLine = 0;
  5035. var previousName = 0;
  5036. var previousSource = 0;
  5037. var result = '';
  5038. var mapping;
  5039. // The mappings must be guaranteed to be in sorted order before we start
  5040. // serializing them or else the generated line numbers (which are defined
  5041. // via the ';' separators) will be all messed up. Note: it might be more
  5042. // performant to maintain the sorting as we insert them, rather than as we
  5043. // serialize them, but the big O is the same either way.
  5044. this._mappings.sort(util.compareByGeneratedPositions);
  5045. for (var i = 0, len = this._mappings.length; i < len; i++) {
  5046. mapping = this._mappings[i];
  5047. if (mapping.generatedLine !== previousGeneratedLine) {
  5048. previousGeneratedColumn = 0;
  5049. while (mapping.generatedLine !== previousGeneratedLine) {
  5050. result += ';';
  5051. previousGeneratedLine++;
  5052. }
  5053. }
  5054. else {
  5055. if (i > 0) {
  5056. if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) {
  5057. continue;
  5058. }
  5059. result += ',';
  5060. }
  5061. }
  5062. result += base64VLQ.encode(mapping.generatedColumn
  5063. - previousGeneratedColumn);
  5064. previousGeneratedColumn = mapping.generatedColumn;
  5065. if (mapping.source) {
  5066. result += base64VLQ.encode(this._sources.indexOf(mapping.source)
  5067. - previousSource);
  5068. previousSource = this._sources.indexOf(mapping.source);
  5069. // lines are stored 0-based in SourceMap spec version 3
  5070. result += base64VLQ.encode(mapping.originalLine - 1
  5071. - previousOriginalLine);
  5072. previousOriginalLine = mapping.originalLine - 1;
  5073. result += base64VLQ.encode(mapping.originalColumn
  5074. - previousOriginalColumn);
  5075. previousOriginalColumn = mapping.originalColumn;
  5076. if (mapping.name) {
  5077. result += base64VLQ.encode(this._names.indexOf(mapping.name)
  5078. - previousName);
  5079. previousName = this._names.indexOf(mapping.name);
  5080. }
  5081. }
  5082. }
  5083. return result;
  5084. };
  5085. SourceMapGenerator.prototype._generateSourcesContent =
  5086. function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
  5087. return aSources.map(function (source) {
  5088. if (!this._sourcesContents) {
  5089. return null;
  5090. }
  5091. if (aSourceRoot) {
  5092. source = util.relative(aSourceRoot, source);
  5093. }
  5094. var key = util.toSetString(source);
  5095. return Object.prototype.hasOwnProperty.call(this._sourcesContents,
  5096. key)
  5097. ? this._sourcesContents[key]
  5098. : null;
  5099. }, this);
  5100. };
  5101. /**
  5102. * Externalize the source map.
  5103. */
  5104. SourceMapGenerator.prototype.toJSON =
  5105. function SourceMapGenerator_toJSON() {
  5106. var map = {
  5107. version: this._version,
  5108. file: this._file,
  5109. sources: this._sources.toArray(),
  5110. names: this._names.toArray(),
  5111. mappings: this._serializeMappings()
  5112. };
  5113. if (this._sourceRoot) {
  5114. map.sourceRoot = this._sourceRoot;
  5115. }
  5116. if (this._sourcesContents) {
  5117. map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
  5118. }
  5119. return map;
  5120. };
  5121. /**
  5122. * Render the source map being generated to a string.
  5123. */
  5124. SourceMapGenerator.prototype.toString =
  5125. function SourceMapGenerator_toString() {
  5126. return JSON.stringify(this);
  5127. };
  5128. exports.SourceMapGenerator = SourceMapGenerator;
  5129. });
  5130. },{"./array-set":36,"./base64-vlq":37,"./util":43,"amdefine":44}],42:[function(require,module,exports){
  5131. /* -*- Mode: js; js-indent-level: 2; -*- */
  5132. /*
  5133. * Copyright 2011 Mozilla Foundation and contributors
  5134. * Licensed under the New BSD license. See LICENSE or:
  5135. * http://opensource.org/licenses/BSD-3-Clause
  5136. */
  5137. if (typeof define !== 'function') {
  5138. var define = require('amdefine')(module, require);
  5139. }
  5140. define(function (require, exports, module) {
  5141. var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;
  5142. var util = require('./util');
  5143. /**
  5144. * SourceNodes provide a way to abstract over interpolating/concatenating
  5145. * snippets of generated JavaScript source code while maintaining the line and
  5146. * column information associated with the original source code.
  5147. *
  5148. * @param aLine The original line number.
  5149. * @param aColumn The original column number.
  5150. * @param aSource The original source's filename.
  5151. * @param aChunks Optional. An array of strings which are snippets of
  5152. * generated JS, or other SourceNodes.
  5153. * @param aName The original identifier.
  5154. */
  5155. function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
  5156. this.children = [];
  5157. this.sourceContents = {};
  5158. this.line = aLine === undefined ? null : aLine;
  5159. this.column = aColumn === undefined ? null : aColumn;
  5160. this.source = aSource === undefined ? null : aSource;
  5161. this.name = aName === undefined ? null : aName;
  5162. if (aChunks != null) this.add(aChunks);
  5163. }
  5164. /**
  5165. * Creates a SourceNode from generated code and a SourceMapConsumer.
  5166. *
  5167. * @param aGeneratedCode The generated code
  5168. * @param aSourceMapConsumer The SourceMap for the generated code
  5169. */
  5170. SourceNode.fromStringWithSourceMap =
  5171. function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
  5172. // The SourceNode we want to fill with the generated code
  5173. // and the SourceMap
  5174. var node = new SourceNode();
  5175. // The generated code
  5176. // Processed fragments are removed from this array.
  5177. var remainingLines = aGeneratedCode.split('\n');
  5178. // We need to remember the position of "remainingLines"
  5179. var lastGeneratedLine = 1, lastGeneratedColumn = 0;
  5180. // The generate SourceNodes we need a code range.
  5181. // To extract it current and last mapping is used.
  5182. // Here we store the last mapping.
  5183. var lastMapping = null;
  5184. aSourceMapConsumer.eachMapping(function (mapping) {
  5185. if (lastMapping === null) {
  5186. // We add the generated code until the first mapping
  5187. // to the SourceNode without any mapping.
  5188. // Each line is added as separate string.
  5189. while (lastGeneratedLine < mapping.generatedLine) {
  5190. node.add(remainingLines.shift() + "\n");
  5191. lastGeneratedLine++;
  5192. }
  5193. if (lastGeneratedColumn < mapping.generatedColumn) {
  5194. var nextLine = remainingLines[0];
  5195. node.add(nextLine.substr(0, mapping.generatedColumn));
  5196. remainingLines[0] = nextLine.substr(mapping.generatedColumn);
  5197. lastGeneratedColumn = mapping.generatedColumn;
  5198. }
  5199. } else {
  5200. // We add the code from "lastMapping" to "mapping":
  5201. // First check if there is a new line in between.
  5202. if (lastGeneratedLine < mapping.generatedLine) {
  5203. var code = "";
  5204. // Associate full lines with "lastMapping"
  5205. do {
  5206. code += remainingLines.shift() + "\n";
  5207. lastGeneratedLine++;
  5208. lastGeneratedColumn = 0;
  5209. } while (lastGeneratedLine < mapping.generatedLine);
  5210. // When we reached the correct line, we add code until we
  5211. // reach the correct column too.
  5212. if (lastGeneratedColumn < mapping.generatedColumn) {
  5213. var nextLine = remainingLines[0];
  5214. code += nextLine.substr(0, mapping.generatedColumn);
  5215. remainingLines[0] = nextLine.substr(mapping.generatedColumn);
  5216. lastGeneratedColumn = mapping.generatedColumn;
  5217. }
  5218. // Create the SourceNode.
  5219. addMappingWithCode(lastMapping, code);
  5220. } else {
  5221. // There is no new line in between.
  5222. // Associate the code between "lastGeneratedColumn" and
  5223. // "mapping.generatedColumn" with "lastMapping"
  5224. var nextLine = remainingLines[0];
  5225. var code = nextLine.substr(0, mapping.generatedColumn -
  5226. lastGeneratedColumn);
  5227. remainingLines[0] = nextLine.substr(mapping.generatedColumn -
  5228. lastGeneratedColumn);
  5229. lastGeneratedColumn = mapping.generatedColumn;
  5230. addMappingWithCode(lastMapping, code);
  5231. }
  5232. }
  5233. lastMapping = mapping;
  5234. }, this);
  5235. // We have processed all mappings.
  5236. // Associate the remaining code in the current line with "lastMapping"
  5237. // and add the remaining lines without any mapping
  5238. addMappingWithCode(lastMapping, remainingLines.join("\n"));
  5239. // Copy sourcesContent into SourceNode
  5240. aSourceMapConsumer.sources.forEach(function (sourceFile) {
  5241. var content = aSourceMapConsumer.sourceContentFor(sourceFile);
  5242. if (content) {
  5243. node.setSourceContent(sourceFile, content);
  5244. }
  5245. });
  5246. return node;
  5247. function addMappingWithCode(mapping, code) {
  5248. if (mapping === null || mapping.source === undefined) {
  5249. node.add(code);
  5250. } else {
  5251. node.add(new SourceNode(mapping.originalLine,
  5252. mapping.originalColumn,
  5253. mapping.source,
  5254. code,
  5255. mapping.name));
  5256. }
  5257. }
  5258. };
  5259. /**
  5260. * Add a chunk of generated JS to this source node.
  5261. *
  5262. * @param aChunk A string snippet of generated JS code, another instance of
  5263. * SourceNode, or an array where each member is one of those things.
  5264. */
  5265. SourceNode.prototype.add = function SourceNode_add(aChunk) {
  5266. if (Array.isArray(aChunk)) {
  5267. aChunk.forEach(function (chunk) {
  5268. this.add(chunk);
  5269. }, this);
  5270. }
  5271. else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
  5272. if (aChunk) {
  5273. this.children.push(aChunk);
  5274. }
  5275. }
  5276. else {
  5277. throw new TypeError(
  5278. "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
  5279. );
  5280. }
  5281. return this;
  5282. };
  5283. /**
  5284. * Add a chunk of generated JS to the beginning of this source node.
  5285. *
  5286. * @param aChunk A string snippet of generated JS code, another instance of
  5287. * SourceNode, or an array where each member is one of those things.
  5288. */
  5289. SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
  5290. if (Array.isArray(aChunk)) {
  5291. for (var i = aChunk.length-1; i >= 0; i--) {
  5292. this.prepend(aChunk[i]);
  5293. }
  5294. }
  5295. else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
  5296. this.children.unshift(aChunk);
  5297. }
  5298. else {
  5299. throw new TypeError(
  5300. "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
  5301. );
  5302. }
  5303. return this;
  5304. };
  5305. /**
  5306. * Walk over the tree of JS snippets in this node and its children. The
  5307. * walking function is called once for each snippet of JS and is passed that
  5308. * snippet and the its original associated source's line/column location.
  5309. *
  5310. * @param aFn The traversal function.
  5311. */
  5312. SourceNode.prototype.walk = function SourceNode_walk(aFn) {
  5313. var chunk;
  5314. for (var i = 0, len = this.children.length; i < len; i++) {
  5315. chunk = this.children[i];
  5316. if (chunk instanceof SourceNode) {
  5317. chunk.walk(aFn);
  5318. }
  5319. else {
  5320. if (chunk !== '') {
  5321. aFn(chunk, { source: this.source,
  5322. line: this.line,
  5323. column: this.column,
  5324. name: this.name });
  5325. }
  5326. }
  5327. }
  5328. };
  5329. /**
  5330. * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
  5331. * each of `this.children`.
  5332. *
  5333. * @param aSep The separator.
  5334. */
  5335. SourceNode.prototype.join = function SourceNode_join(aSep) {
  5336. var newChildren;
  5337. var i;
  5338. var len = this.children.length;
  5339. if (len > 0) {
  5340. newChildren = [];
  5341. for (i = 0; i < len-1; i++) {
  5342. newChildren.push(this.children[i]);
  5343. newChildren.push(aSep);
  5344. }
  5345. newChildren.push(this.children[i]);
  5346. this.children = newChildren;
  5347. }
  5348. return this;
  5349. };
  5350. /**
  5351. * Call String.prototype.replace on the very right-most source snippet. Useful
  5352. * for trimming whitespace from the end of a source node, etc.
  5353. *
  5354. * @param aPattern The pattern to replace.
  5355. * @param aReplacement The thing to replace the pattern with.
  5356. */
  5357. SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
  5358. var lastChild = this.children[this.children.length - 1];
  5359. if (lastChild instanceof SourceNode) {
  5360. lastChild.replaceRight(aPattern, aReplacement);
  5361. }
  5362. else if (typeof lastChild === 'string') {
  5363. this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
  5364. }
  5365. else {
  5366. this.children.push(''.replace(aPattern, aReplacement));
  5367. }
  5368. return this;
  5369. };
  5370. /**
  5371. * Set the source content for a source file. This will be added to the SourceMapGenerator
  5372. * in the sourcesContent field.
  5373. *
  5374. * @param aSourceFile The filename of the source file
  5375. * @param aSourceContent The content of the source file
  5376. */
  5377. SourceNode.prototype.setSourceContent =
  5378. function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
  5379. this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
  5380. };
  5381. /**
  5382. * Walk over the tree of SourceNodes. The walking function is called for each
  5383. * source file content and is passed the filename and source content.
  5384. *
  5385. * @param aFn The traversal function.
  5386. */
  5387. SourceNode.prototype.walkSourceContents =
  5388. function SourceNode_walkSourceContents(aFn) {
  5389. for (var i = 0, len = this.children.length; i < len; i++) {
  5390. if (this.children[i] instanceof SourceNode) {
  5391. this.children[i].walkSourceContents(aFn);
  5392. }
  5393. }
  5394. var sources = Object.keys(this.sourceContents);
  5395. for (var i = 0, len = sources.length; i < len; i++) {
  5396. aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
  5397. }
  5398. };
  5399. /**
  5400. * Return the string representation of this source node. Walks over the tree
  5401. * and concatenates all the various snippets together to one string.
  5402. */
  5403. SourceNode.prototype.toString = function SourceNode_toString() {
  5404. var str = "";
  5405. this.walk(function (chunk) {
  5406. str += chunk;
  5407. });
  5408. return str;
  5409. };
  5410. /**
  5411. * Returns the string representation of this source node along with a source
  5412. * map.
  5413. */
  5414. SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
  5415. var generated = {
  5416. code: "",
  5417. line: 1,
  5418. column: 0
  5419. };
  5420. var map = new SourceMapGenerator(aArgs);
  5421. var sourceMappingActive = false;
  5422. var lastOriginalSource = null;
  5423. var lastOriginalLine = null;
  5424. var lastOriginalColumn = null;
  5425. var lastOriginalName = null;
  5426. this.walk(function (chunk, original) {
  5427. generated.code += chunk;
  5428. if (original.source !== null
  5429. && original.line !== null
  5430. && original.column !== null) {
  5431. if(lastOriginalSource !== original.source
  5432. || lastOriginalLine !== original.line
  5433. || lastOriginalColumn !== original.column
  5434. || lastOriginalName !== original.name) {
  5435. map.addMapping({
  5436. source: original.source,
  5437. original: {
  5438. line: original.line,
  5439. column: original.column
  5440. },
  5441. generated: {
  5442. line: generated.line,
  5443. column: generated.column
  5444. },
  5445. name: original.name
  5446. });
  5447. }
  5448. lastOriginalSource = original.source;
  5449. lastOriginalLine = original.line;
  5450. lastOriginalColumn = original.column;
  5451. lastOriginalName = original.name;
  5452. sourceMappingActive = true;
  5453. } else if (sourceMappingActive) {
  5454. map.addMapping({
  5455. generated: {
  5456. line: generated.line,
  5457. column: generated.column
  5458. }
  5459. });
  5460. lastOriginalSource = null;
  5461. sourceMappingActive = false;
  5462. }
  5463. chunk.split('').forEach(function (ch) {
  5464. if (ch === '\n') {
  5465. generated.line++;
  5466. generated.column = 0;
  5467. } else {
  5468. generated.column++;
  5469. }
  5470. });
  5471. });
  5472. this.walkSourceContents(function (sourceFile, sourceContent) {
  5473. map.setSourceContent(sourceFile, sourceContent);
  5474. });
  5475. return { code: generated.code, map: map };
  5476. };
  5477. exports.SourceNode = SourceNode;
  5478. });
  5479. },{"./source-map-generator":41,"./util":43,"amdefine":44}],43:[function(require,module,exports){
  5480. /* -*- Mode: js; js-indent-level: 2; -*- */
  5481. /*
  5482. * Copyright 2011 Mozilla Foundation and contributors
  5483. * Licensed under the New BSD license. See LICENSE or:
  5484. * http://opensource.org/licenses/BSD-3-Clause
  5485. */
  5486. if (typeof define !== 'function') {
  5487. var define = require('amdefine')(module, require);
  5488. }
  5489. define(function (require, exports, module) {
  5490. /**
  5491. * This is a helper function for getting values from parameter/options
  5492. * objects.
  5493. *
  5494. * @param args The object we are extracting values from
  5495. * @param name The name of the property we are getting.
  5496. * @param defaultValue An optional value to return if the property is missing
  5497. * from the object. If this is not specified and the property is missing, an
  5498. * error will be thrown.
  5499. */
  5500. function getArg(aArgs, aName, aDefaultValue) {
  5501. if (aName in aArgs) {
  5502. return aArgs[aName];
  5503. } else if (arguments.length === 3) {
  5504. return aDefaultValue;
  5505. } else {
  5506. throw new Error('"' + aName + '" is a required argument.');
  5507. }
  5508. }
  5509. exports.getArg = getArg;
  5510. var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
  5511. var dataUrlRegexp = /^data:.+\,.+/;
  5512. function urlParse(aUrl) {
  5513. var match = aUrl.match(urlRegexp);
  5514. if (!match) {
  5515. return null;
  5516. }
  5517. return {
  5518. scheme: match[1],
  5519. auth: match[3],
  5520. host: match[4],
  5521. port: match[6],
  5522. path: match[7]
  5523. };
  5524. }
  5525. exports.urlParse = urlParse;
  5526. function urlGenerate(aParsedUrl) {
  5527. var url = aParsedUrl.scheme + "://";
  5528. if (aParsedUrl.auth) {
  5529. url += aParsedUrl.auth + "@"
  5530. }
  5531. if (aParsedUrl.host) {
  5532. url += aParsedUrl.host;
  5533. }
  5534. if (aParsedUrl.port) {
  5535. url += ":" + aParsedUrl.port
  5536. }
  5537. if (aParsedUrl.path) {
  5538. url += aParsedUrl.path;
  5539. }
  5540. return url;
  5541. }
  5542. exports.urlGenerate = urlGenerate;
  5543. function join(aRoot, aPath) {
  5544. var url;
  5545. if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) {
  5546. return aPath;
  5547. }
  5548. if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
  5549. url.path = aPath;
  5550. return urlGenerate(url);
  5551. }
  5552. return aRoot.replace(/\/$/, '') + '/' + aPath;
  5553. }
  5554. exports.join = join;
  5555. /**
  5556. * Because behavior goes wacky when you set `__proto__` on objects, we
  5557. * have to prefix all the strings in our set with an arbitrary character.
  5558. *
  5559. * See https://github.com/mozilla/source-map/pull/31 and
  5560. * https://github.com/mozilla/source-map/issues/30
  5561. *
  5562. * @param String aStr
  5563. */
  5564. function toSetString(aStr) {
  5565. return '$' + aStr;
  5566. }
  5567. exports.toSetString = toSetString;
  5568. function fromSetString(aStr) {
  5569. return aStr.substr(1);
  5570. }
  5571. exports.fromSetString = fromSetString;
  5572. function relative(aRoot, aPath) {
  5573. aRoot = aRoot.replace(/\/$/, '');
  5574. var url = urlParse(aRoot);
  5575. if (aPath.charAt(0) == "/" && url && url.path == "/") {
  5576. return aPath.slice(1);
  5577. }
  5578. return aPath.indexOf(aRoot + '/') === 0
  5579. ? aPath.substr(aRoot.length + 1)
  5580. : aPath;
  5581. }
  5582. exports.relative = relative;
  5583. function strcmp(aStr1, aStr2) {
  5584. var s1 = aStr1 || "";
  5585. var s2 = aStr2 || "";
  5586. return (s1 > s2) - (s1 < s2);
  5587. }
  5588. /**
  5589. * Comparator between two mappings where the original positions are compared.
  5590. *
  5591. * Optionally pass in `true` as `onlyCompareGenerated` to consider two
  5592. * mappings with the same original source/line/column, but different generated
  5593. * line and column the same. Useful when searching for a mapping with a
  5594. * stubbed out mapping.
  5595. */
  5596. function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
  5597. var cmp;
  5598. cmp = strcmp(mappingA.source, mappingB.source);
  5599. if (cmp) {
  5600. return cmp;
  5601. }
  5602. cmp = mappingA.originalLine - mappingB.originalLine;
  5603. if (cmp) {
  5604. return cmp;
  5605. }
  5606. cmp = mappingA.originalColumn - mappingB.originalColumn;
  5607. if (cmp || onlyCompareOriginal) {
  5608. return cmp;
  5609. }
  5610. cmp = strcmp(mappingA.name, mappingB.name);
  5611. if (cmp) {
  5612. return cmp;
  5613. }
  5614. cmp = mappingA.generatedLine - mappingB.generatedLine;
  5615. if (cmp) {
  5616. return cmp;
  5617. }
  5618. return mappingA.generatedColumn - mappingB.generatedColumn;
  5619. };
  5620. exports.compareByOriginalPositions = compareByOriginalPositions;
  5621. /**
  5622. * Comparator between two mappings where the generated positions are
  5623. * compared.
  5624. *
  5625. * Optionally pass in `true` as `onlyCompareGenerated` to consider two
  5626. * mappings with the same generated line and column, but different
  5627. * source/name/original line and column the same. Useful when searching for a
  5628. * mapping with a stubbed out mapping.
  5629. */
  5630. function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
  5631. var cmp;
  5632. cmp = mappingA.generatedLine - mappingB.generatedLine;
  5633. if (cmp) {
  5634. return cmp;
  5635. }
  5636. cmp = mappingA.generatedColumn - mappingB.generatedColumn;
  5637. if (cmp || onlyCompareGenerated) {
  5638. return cmp;
  5639. }
  5640. cmp = strcmp(mappingA.source, mappingB.source);
  5641. if (cmp) {
  5642. return cmp;
  5643. }
  5644. cmp = mappingA.originalLine - mappingB.originalLine;
  5645. if (cmp) {
  5646. return cmp;
  5647. }
  5648. cmp = mappingA.originalColumn - mappingB.originalColumn;
  5649. if (cmp) {
  5650. return cmp;
  5651. }
  5652. return strcmp(mappingA.name, mappingB.name);
  5653. };
  5654. exports.compareByGeneratedPositions = compareByGeneratedPositions;
  5655. });
  5656. },{"amdefine":44}],44:[function(require,module,exports){
  5657. var process=require("__browserify_process"),__filename="/../node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js";/** vim: et:ts=4:sw=4:sts=4
  5658. * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
  5659. * Available via the MIT or new BSD license.
  5660. * see: http://github.com/jrburke/amdefine for details
  5661. */
  5662. /*jslint node: true */
  5663. /*global module, process */
  5664. 'use strict';
  5665. /**
  5666. * Creates a define for node.
  5667. * @param {Object} module the "module" object that is defined by Node for the
  5668. * current module.
  5669. * @param {Function} [requireFn]. Node's require function for the current module.
  5670. * It only needs to be passed in Node versions before 0.5, when module.require
  5671. * did not exist.
  5672. * @returns {Function} a define function that is usable for the current node
  5673. * module.
  5674. */
  5675. function amdefine(module, requireFn) {
  5676. 'use strict';
  5677. var defineCache = {},
  5678. loaderCache = {},
  5679. alreadyCalled = false,
  5680. path = require('path'),
  5681. makeRequire, stringRequire;
  5682. /**
  5683. * Trims the . and .. from an array of path segments.
  5684. * It will keep a leading path segment if a .. will become
  5685. * the first path segment, to help with module name lookups,
  5686. * which act like paths, but can be remapped. But the end result,
  5687. * all paths that use this function should look normalized.
  5688. * NOTE: this method MODIFIES the input array.
  5689. * @param {Array} ary the array of path segments.
  5690. */
  5691. function trimDots(ary) {
  5692. var i, part;
  5693. for (i = 0; ary[i]; i+= 1) {
  5694. part = ary[i];
  5695. if (part === '.') {
  5696. ary.splice(i, 1);
  5697. i -= 1;
  5698. } else if (part === '..') {
  5699. if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
  5700. //End of the line. Keep at least one non-dot
  5701. //path segment at the front so it can be mapped
  5702. //correctly to disk. Otherwise, there is likely
  5703. //no path mapping for a path starting with '..'.
  5704. //This can still fail, but catches the most reasonable
  5705. //uses of ..
  5706. break;
  5707. } else if (i > 0) {
  5708. ary.splice(i - 1, 2);
  5709. i -= 2;
  5710. }
  5711. }
  5712. }
  5713. }
  5714. function normalize(name, baseName) {
  5715. var baseParts;
  5716. //Adjust any relative paths.
  5717. if (name && name.charAt(0) === '.') {
  5718. //If have a base name, try to normalize against it,
  5719. //otherwise, assume it is a top-level require that will
  5720. //be relative to baseUrl in the end.
  5721. if (baseName) {
  5722. baseParts = baseName.split('/');
  5723. baseParts = baseParts.slice(0, baseParts.length - 1);
  5724. baseParts = baseParts.concat(name.split('/'));
  5725. trimDots(baseParts);
  5726. name = baseParts.join('/');
  5727. }
  5728. }
  5729. return name;
  5730. }
  5731. /**
  5732. * Create the normalize() function passed to a loader plugin's
  5733. * normalize method.
  5734. */
  5735. function makeNormalize(relName) {
  5736. return function (name) {
  5737. return normalize(name, relName);
  5738. };
  5739. }
  5740. function makeLoad(id) {
  5741. function load(value) {
  5742. loaderCache[id] = value;
  5743. }
  5744. load.fromText = function (id, text) {
  5745. //This one is difficult because the text can/probably uses
  5746. //define, and any relative paths and requires should be relative
  5747. //to that id was it would be found on disk. But this would require
  5748. //bootstrapping a module/require fairly deeply from node core.
  5749. //Not sure how best to go about that yet.
  5750. throw new Error('amdefine does not implement load.fromText');
  5751. };
  5752. return load;
  5753. }
  5754. makeRequire = function (systemRequire, exports, module, relId) {
  5755. function amdRequire(deps, callback) {
  5756. if (typeof deps === 'string') {
  5757. //Synchronous, single module require('')
  5758. return stringRequire(systemRequire, exports, module, deps, relId);
  5759. } else {
  5760. //Array of dependencies with a callback.
  5761. //Convert the dependencies to modules.
  5762. deps = deps.map(function (depName) {
  5763. return stringRequire(systemRequire, exports, module, depName, relId);
  5764. });
  5765. //Wait for next tick to call back the require call.
  5766. process.nextTick(function () {
  5767. callback.apply(null, deps);
  5768. });
  5769. }
  5770. }
  5771. amdRequire.toUrl = function (filePath) {
  5772. if (filePath.indexOf('.') === 0) {
  5773. return normalize(filePath, path.dirname(module.filename));
  5774. } else {
  5775. return filePath;
  5776. }
  5777. };
  5778. return amdRequire;
  5779. };
  5780. //Favor explicit value, passed in if the module wants to support Node 0.4.
  5781. requireFn = requireFn || function req() {
  5782. return module.require.apply(module, arguments);
  5783. };
  5784. function runFactory(id, deps, factory) {
  5785. var r, e, m, result;
  5786. if (id) {
  5787. e = loaderCache[id] = {};
  5788. m = {
  5789. id: id,
  5790. uri: __filename,
  5791. exports: e
  5792. };
  5793. r = makeRequire(requireFn, e, m, id);
  5794. } else {
  5795. //Only support one define call per file
  5796. if (alreadyCalled) {
  5797. throw new Error('amdefine with no module ID cannot be called more than once per file.');
  5798. }
  5799. alreadyCalled = true;
  5800. //Use the real variables from node
  5801. //Use module.exports for exports, since
  5802. //the exports in here is amdefine exports.
  5803. e = module.exports;
  5804. m = module;
  5805. r = makeRequire(requireFn, e, m, module.id);
  5806. }
  5807. //If there are dependencies, they are strings, so need
  5808. //to convert them to dependency values.
  5809. if (deps) {
  5810. deps = deps.map(function (depName) {
  5811. return r(depName);
  5812. });
  5813. }
  5814. //Call the factory with the right dependencies.
  5815. if (typeof factory === 'function') {
  5816. result = factory.apply(m.exports, deps);
  5817. } else {
  5818. result = factory;
  5819. }
  5820. if (result !== undefined) {
  5821. m.exports = result;
  5822. if (id) {
  5823. loaderCache[id] = m.exports;
  5824. }
  5825. }
  5826. }
  5827. stringRequire = function (systemRequire, exports, module, id, relId) {
  5828. //Split the ID by a ! so that
  5829. var index = id.indexOf('!'),
  5830. originalId = id,
  5831. prefix, plugin;
  5832. if (index === -1) {
  5833. id = normalize(id, relId);
  5834. //Straight module lookup. If it is one of the special dependencies,
  5835. //deal with it, otherwise, delegate to node.
  5836. if (id === 'require') {
  5837. return makeRequire(systemRequire, exports, module, relId);
  5838. } else if (id === 'exports') {
  5839. return exports;
  5840. } else if (id === 'module') {
  5841. return module;
  5842. } else if (loaderCache.hasOwnProperty(id)) {
  5843. return loaderCache[id];
  5844. } else if (defineCache[id]) {
  5845. runFactory.apply(null, defineCache[id]);
  5846. return loaderCache[id];
  5847. } else {
  5848. if(systemRequire) {
  5849. return systemRequire(originalId);
  5850. } else {
  5851. throw new Error('No module with ID: ' + id);
  5852. }
  5853. }
  5854. } else {
  5855. //There is a plugin in play.
  5856. prefix = id.substring(0, index);
  5857. id = id.substring(index + 1, id.length);
  5858. plugin = stringRequire(systemRequire, exports, module, prefix, relId);
  5859. if (plugin.normalize) {
  5860. id = plugin.normalize(id, makeNormalize(relId));
  5861. } else {
  5862. //Normalize the ID normally.
  5863. id = normalize(id, relId);
  5864. }
  5865. if (loaderCache[id]) {
  5866. return loaderCache[id];
  5867. } else {
  5868. plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
  5869. return loaderCache[id];
  5870. }
  5871. }
  5872. };
  5873. //Create a define function specific to the module asking for amdefine.
  5874. function define(id, deps, factory) {
  5875. if (Array.isArray(id)) {
  5876. factory = deps;
  5877. deps = id;
  5878. id = undefined;
  5879. } else if (typeof id !== 'string') {
  5880. factory = id;
  5881. id = deps = undefined;
  5882. }
  5883. if (deps && !Array.isArray(deps)) {
  5884. factory = deps;
  5885. deps = undefined;
  5886. }
  5887. if (!deps) {
  5888. deps = ['require', 'exports', 'module'];
  5889. }
  5890. //Set up properties for this module. If an ID, then use
  5891. //internal cache. If no ID, then use the external variables
  5892. //for this node module.
  5893. if (id) {
  5894. //Put the module in deep freeze until there is a
  5895. //require call for it.
  5896. defineCache[id] = [id, deps, factory];
  5897. } else {
  5898. runFactory(id, deps, factory);
  5899. }
  5900. }
  5901. //define.require, which has access to all the values in the
  5902. //cache. Useful for AMD modules that all have IDs in the file,
  5903. //but need to finally export a value to node based on one of those
  5904. //IDs.
  5905. define.require = function (id) {
  5906. if (loaderCache[id]) {
  5907. return loaderCache[id];
  5908. }
  5909. if (defineCache[id]) {
  5910. runFactory.apply(null, defineCache[id]);
  5911. return loaderCache[id];
  5912. }
  5913. };
  5914. define.amd = {};
  5915. return define;
  5916. }
  5917. module.exports = amdefine;
  5918. },{"__browserify_process":29,"path":30}],45:[function(require,module,exports){
  5919. var sys = require("util");
  5920. var MOZ_SourceMap = require("source-map");
  5921. var UglifyJS = exports;
  5922. /***********************************************************************
  5923. A JavaScript tokenizer / parser / beautifier / compressor.
  5924. https://github.com/mishoo/UglifyJS2
  5925. -------------------------------- (C) ---------------------------------
  5926. Author: Mihai Bazon
  5927. <mihai.bazon@gmail.com>
  5928. http://mihai.bazon.net/blog
  5929. Distributed under the BSD license:
  5930. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  5931. Redistribution and use in source and binary forms, with or without
  5932. modification, are permitted provided that the following conditions
  5933. are met:
  5934. * Redistributions of source code must retain the above
  5935. copyright notice, this list of conditions and the following
  5936. disclaimer.
  5937. * Redistributions in binary form must reproduce the above
  5938. copyright notice, this list of conditions and the following
  5939. disclaimer in the documentation and/or other materials
  5940. provided with the distribution.
  5941. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  5942. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  5943. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  5944. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  5945. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  5946. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  5947. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  5948. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  5949. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  5950. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  5951. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  5952. SUCH DAMAGE.
  5953. ***********************************************************************/
  5954. "use strict";
  5955. function array_to_hash(a) {
  5956. var ret = Object.create(null);
  5957. for (var i = 0; i < a.length; ++i)
  5958. ret[a[i]] = true;
  5959. return ret;
  5960. };
  5961. function slice(a, start) {
  5962. return Array.prototype.slice.call(a, start || 0);
  5963. };
  5964. function characters(str) {
  5965. return str.split("");
  5966. };
  5967. function member(name, array) {
  5968. for (var i = array.length; --i >= 0;)
  5969. if (array[i] == name)
  5970. return true;
  5971. return false;
  5972. };
  5973. function find_if(func, array) {
  5974. for (var i = 0, n = array.length; i < n; ++i) {
  5975. if (func(array[i]))
  5976. return array[i];
  5977. }
  5978. };
  5979. function repeat_string(str, i) {
  5980. if (i <= 0) return "";
  5981. if (i == 1) return str;
  5982. var d = repeat_string(str, i >> 1);
  5983. d += d;
  5984. if (i & 1) d += str;
  5985. return d;
  5986. };
  5987. function DefaultsError(msg, defs) {
  5988. Error.call(this, msg);
  5989. this.msg = msg;
  5990. this.defs = defs;
  5991. };
  5992. DefaultsError.prototype = Object.create(Error.prototype);
  5993. DefaultsError.prototype.constructor = DefaultsError;
  5994. DefaultsError.croak = function(msg, defs) {
  5995. throw new DefaultsError(msg, defs);
  5996. };
  5997. function defaults(args, defs, croak) {
  5998. if (args === true)
  5999. args = {};
  6000. var ret = args || {};
  6001. if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
  6002. DefaultsError.croak("`" + i + "` is not a supported option", defs);
  6003. for (var i in defs) if (defs.hasOwnProperty(i)) {
  6004. ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
  6005. }
  6006. return ret;
  6007. };
  6008. function merge(obj, ext) {
  6009. for (var i in ext) if (ext.hasOwnProperty(i)) {
  6010. obj[i] = ext[i];
  6011. }
  6012. return obj;
  6013. };
  6014. function noop() {};
  6015. var MAP = (function(){
  6016. function MAP(a, f, backwards) {
  6017. var ret = [], top = [], i;
  6018. function doit() {
  6019. var val = f(a[i], i);
  6020. var is_last = val instanceof Last;
  6021. if (is_last) val = val.v;
  6022. if (val instanceof AtTop) {
  6023. val = val.v;
  6024. if (val instanceof Splice) {
  6025. top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
  6026. } else {
  6027. top.push(val);
  6028. }
  6029. }
  6030. else if (val !== skip) {
  6031. if (val instanceof Splice) {
  6032. ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
  6033. } else {
  6034. ret.push(val);
  6035. }
  6036. }
  6037. return is_last;
  6038. };
  6039. if (a instanceof Array) {
  6040. if (backwards) {
  6041. for (i = a.length; --i >= 0;) if (doit()) break;
  6042. ret.reverse();
  6043. top.reverse();
  6044. } else {
  6045. for (i = 0; i < a.length; ++i) if (doit()) break;
  6046. }
  6047. }
  6048. else {
  6049. for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
  6050. }
  6051. return top.concat(ret);
  6052. };
  6053. MAP.at_top = function(val) { return new AtTop(val) };
  6054. MAP.splice = function(val) { return new Splice(val) };
  6055. MAP.last = function(val) { return new Last(val) };
  6056. var skip = MAP.skip = {};
  6057. function AtTop(val) { this.v = val };
  6058. function Splice(val) { this.v = val };
  6059. function Last(val) { this.v = val };
  6060. return MAP;
  6061. })();
  6062. function push_uniq(array, el) {
  6063. if (array.indexOf(el) < 0)
  6064. array.push(el);
  6065. };
  6066. function string_template(text, props) {
  6067. return text.replace(/\{(.+?)\}/g, function(str, p){
  6068. return props[p];
  6069. });
  6070. };
  6071. function remove(array, el) {
  6072. for (var i = array.length; --i >= 0;) {
  6073. if (array[i] === el) array.splice(i, 1);
  6074. }
  6075. };
  6076. function mergeSort(array, cmp) {
  6077. if (array.length < 2) return array.slice();
  6078. function merge(a, b) {
  6079. var r = [], ai = 0, bi = 0, i = 0;
  6080. while (ai < a.length && bi < b.length) {
  6081. cmp(a[ai], b[bi]) <= 0
  6082. ? r[i++] = a[ai++]
  6083. : r[i++] = b[bi++];
  6084. }
  6085. if (ai < a.length) r.push.apply(r, a.slice(ai));
  6086. if (bi < b.length) r.push.apply(r, b.slice(bi));
  6087. return r;
  6088. };
  6089. function _ms(a) {
  6090. if (a.length <= 1)
  6091. return a;
  6092. var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
  6093. left = _ms(left);
  6094. right = _ms(right);
  6095. return merge(left, right);
  6096. };
  6097. return _ms(array);
  6098. };
  6099. function set_difference(a, b) {
  6100. return a.filter(function(el){
  6101. return b.indexOf(el) < 0;
  6102. });
  6103. };
  6104. function set_intersection(a, b) {
  6105. return a.filter(function(el){
  6106. return b.indexOf(el) >= 0;
  6107. });
  6108. };
  6109. // this function is taken from Acorn [1], written by Marijn Haverbeke
  6110. // [1] https://github.com/marijnh/acorn
  6111. function makePredicate(words) {
  6112. if (!(words instanceof Array)) words = words.split(" ");
  6113. var f = "", cats = [];
  6114. out: for (var i = 0; i < words.length; ++i) {
  6115. for (var j = 0; j < cats.length; ++j)
  6116. if (cats[j][0].length == words[i].length) {
  6117. cats[j].push(words[i]);
  6118. continue out;
  6119. }
  6120. cats.push([words[i]]);
  6121. }
  6122. function compareTo(arr) {
  6123. if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
  6124. f += "switch(str){";
  6125. for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
  6126. f += "return true}return false;";
  6127. }
  6128. // When there are more than three length categories, an outer
  6129. // switch first dispatches on the lengths, to save on comparisons.
  6130. if (cats.length > 3) {
  6131. cats.sort(function(a, b) {return b.length - a.length;});
  6132. f += "switch(str.length){";
  6133. for (var i = 0; i < cats.length; ++i) {
  6134. var cat = cats[i];
  6135. f += "case " + cat[0].length + ":";
  6136. compareTo(cat);
  6137. }
  6138. f += "}";
  6139. // Otherwise, simply generate a flat `switch` statement.
  6140. } else {
  6141. compareTo(words);
  6142. }
  6143. return new Function("str", f);
  6144. };
  6145. function all(array, predicate) {
  6146. for (var i = array.length; --i >= 0;)
  6147. if (!predicate(array[i]))
  6148. return false;
  6149. return true;
  6150. };
  6151. function Dictionary() {
  6152. this._values = Object.create(null);
  6153. this._size = 0;
  6154. };
  6155. Dictionary.prototype = {
  6156. set: function(key, val) {
  6157. if (!this.has(key)) ++this._size;
  6158. this._values["$" + key] = val;
  6159. return this;
  6160. },
  6161. add: function(key, val) {
  6162. if (this.has(key)) {
  6163. this.get(key).push(val);
  6164. } else {
  6165. this.set(key, [ val ]);
  6166. }
  6167. return this;
  6168. },
  6169. get: function(key) { return this._values["$" + key] },
  6170. del: function(key) {
  6171. if (this.has(key)) {
  6172. --this._size;
  6173. delete this._values["$" + key];
  6174. }
  6175. return this;
  6176. },
  6177. has: function(key) { return ("$" + key) in this._values },
  6178. each: function(f) {
  6179. for (var i in this._values)
  6180. f(this._values[i], i.substr(1));
  6181. },
  6182. size: function() {
  6183. return this._size;
  6184. },
  6185. map: function(f) {
  6186. var ret = [];
  6187. for (var i in this._values)
  6188. ret.push(f(this._values[i], i.substr(1)));
  6189. return ret;
  6190. }
  6191. };
  6192. /***********************************************************************
  6193. A JavaScript tokenizer / parser / beautifier / compressor.
  6194. https://github.com/mishoo/UglifyJS2
  6195. -------------------------------- (C) ---------------------------------
  6196. Author: Mihai Bazon
  6197. <mihai.bazon@gmail.com>
  6198. http://mihai.bazon.net/blog
  6199. Distributed under the BSD license:
  6200. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  6201. Redistribution and use in source and binary forms, with or without
  6202. modification, are permitted provided that the following conditions
  6203. are met:
  6204. * Redistributions of source code must retain the above
  6205. copyright notice, this list of conditions and the following
  6206. disclaimer.
  6207. * Redistributions in binary form must reproduce the above
  6208. copyright notice, this list of conditions and the following
  6209. disclaimer in the documentation and/or other materials
  6210. provided with the distribution.
  6211. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  6212. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  6213. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  6214. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  6215. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  6216. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  6217. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  6218. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  6219. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  6220. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  6221. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  6222. SUCH DAMAGE.
  6223. ***********************************************************************/
  6224. "use strict";
  6225. function DEFNODE(type, props, methods, base) {
  6226. if (arguments.length < 4) base = AST_Node;
  6227. if (!props) props = [];
  6228. else props = props.split(/\s+/);
  6229. var self_props = props;
  6230. if (base && base.PROPS)
  6231. props = props.concat(base.PROPS);
  6232. var code = "return function AST_" + type + "(props){ if (props) { ";
  6233. for (var i = props.length; --i >= 0;) {
  6234. code += "this." + props[i] + " = props." + props[i] + ";";
  6235. }
  6236. var proto = base && new base;
  6237. if (proto && proto.initialize || (methods && methods.initialize))
  6238. code += "this.initialize();";
  6239. code += "}}";
  6240. var ctor = new Function(code)();
  6241. if (proto) {
  6242. ctor.prototype = proto;
  6243. ctor.BASE = base;
  6244. }
  6245. if (base) base.SUBCLASSES.push(ctor);
  6246. ctor.prototype.CTOR = ctor;
  6247. ctor.PROPS = props || null;
  6248. ctor.SELF_PROPS = self_props;
  6249. ctor.SUBCLASSES = [];
  6250. if (type) {
  6251. ctor.prototype.TYPE = ctor.TYPE = type;
  6252. }
  6253. if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
  6254. if (/^\$/.test(i)) {
  6255. ctor[i.substr(1)] = methods[i];
  6256. } else {
  6257. ctor.prototype[i] = methods[i];
  6258. }
  6259. }
  6260. ctor.DEFMETHOD = function(name, method) {
  6261. this.prototype[name] = method;
  6262. };
  6263. return ctor;
  6264. };
  6265. var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {
  6266. }, null);
  6267. var AST_Node = DEFNODE("Node", "start end", {
  6268. clone: function() {
  6269. return new this.CTOR(this);
  6270. },
  6271. $documentation: "Base class of all AST nodes",
  6272. $propdoc: {
  6273. start: "[AST_Token] The first token of this node",
  6274. end: "[AST_Token] The last token of this node"
  6275. },
  6276. _walk: function(visitor) {
  6277. return visitor._visit(this);
  6278. },
  6279. walk: function(visitor) {
  6280. return this._walk(visitor); // not sure the indirection will be any help
  6281. }
  6282. }, null);
  6283. AST_Node.warn_function = null;
  6284. AST_Node.warn = function(txt, props) {
  6285. if (AST_Node.warn_function)
  6286. AST_Node.warn_function(string_template(txt, props));
  6287. };
  6288. /* -----[ statements ]----- */
  6289. var AST_Statement = DEFNODE("Statement", null, {
  6290. $documentation: "Base class of all statements",
  6291. });
  6292. var AST_Debugger = DEFNODE("Debugger", null, {
  6293. $documentation: "Represents a debugger statement",
  6294. }, AST_Statement);
  6295. var AST_Directive = DEFNODE("Directive", "value scope", {
  6296. $documentation: "Represents a directive, like \"use strict\";",
  6297. $propdoc: {
  6298. value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
  6299. scope: "[AST_Scope/S] The scope that this directive affects"
  6300. },
  6301. }, AST_Statement);
  6302. var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
  6303. $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
  6304. $propdoc: {
  6305. body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
  6306. },
  6307. _walk: function(visitor) {
  6308. return visitor._visit(this, function(){
  6309. this.body._walk(visitor);
  6310. });
  6311. }
  6312. }, AST_Statement);
  6313. function walk_body(node, visitor) {
  6314. if (node.body instanceof AST_Statement) {
  6315. node.body._walk(visitor);
  6316. }
  6317. else node.body.forEach(function(stat){
  6318. stat._walk(visitor);
  6319. });
  6320. };
  6321. var AST_Block = DEFNODE("Block", "body", {
  6322. $documentation: "A body of statements (usually bracketed)",
  6323. $propdoc: {
  6324. body: "[AST_Statement*] an array of statements"
  6325. },
  6326. _walk: function(visitor) {
  6327. return visitor._visit(this, function(){
  6328. walk_body(this, visitor);
  6329. });
  6330. }
  6331. }, AST_Statement);
  6332. var AST_BlockStatement = DEFNODE("BlockStatement", null, {
  6333. $documentation: "A block statement",
  6334. }, AST_Block);
  6335. var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
  6336. $documentation: "The empty statement (empty block or simply a semicolon)",
  6337. _walk: function(visitor) {
  6338. return visitor._visit(this);
  6339. }
  6340. }, AST_Statement);
  6341. var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
  6342. $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
  6343. $propdoc: {
  6344. body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
  6345. },
  6346. _walk: function(visitor) {
  6347. return visitor._visit(this, function(){
  6348. this.body._walk(visitor);
  6349. });
  6350. }
  6351. }, AST_Statement);
  6352. var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
  6353. $documentation: "Statement with a label",
  6354. $propdoc: {
  6355. label: "[AST_Label] a label definition"
  6356. },
  6357. _walk: function(visitor) {
  6358. return visitor._visit(this, function(){
  6359. this.label._walk(visitor);
  6360. this.body._walk(visitor);
  6361. });
  6362. }
  6363. }, AST_StatementWithBody);
  6364. var AST_IterationStatement = DEFNODE("IterationStatement", null, {
  6365. $documentation: "Internal class. All loops inherit from it."
  6366. }, AST_StatementWithBody);
  6367. var AST_DWLoop = DEFNODE("DWLoop", "condition", {
  6368. $documentation: "Base class for do/while statements",
  6369. $propdoc: {
  6370. condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
  6371. },
  6372. _walk: function(visitor) {
  6373. return visitor._visit(this, function(){
  6374. this.condition._walk(visitor);
  6375. this.body._walk(visitor);
  6376. });
  6377. }
  6378. }, AST_IterationStatement);
  6379. var AST_Do = DEFNODE("Do", null, {
  6380. $documentation: "A `do` statement",
  6381. }, AST_DWLoop);
  6382. var AST_While = DEFNODE("While", null, {
  6383. $documentation: "A `while` statement",
  6384. }, AST_DWLoop);
  6385. var AST_For = DEFNODE("For", "init condition step", {
  6386. $documentation: "A `for` statement",
  6387. $propdoc: {
  6388. init: "[AST_Node?] the `for` initialization code, or null if empty",
  6389. condition: "[AST_Node?] the `for` termination clause, or null if empty",
  6390. step: "[AST_Node?] the `for` update clause, or null if empty"
  6391. },
  6392. _walk: function(visitor) {
  6393. return visitor._visit(this, function(){
  6394. if (this.init) this.init._walk(visitor);
  6395. if (this.condition) this.condition._walk(visitor);
  6396. if (this.step) this.step._walk(visitor);
  6397. this.body._walk(visitor);
  6398. });
  6399. }
  6400. }, AST_IterationStatement);
  6401. var AST_ForIn = DEFNODE("ForIn", "init name object", {
  6402. $documentation: "A `for ... in` statement",
  6403. $propdoc: {
  6404. init: "[AST_Node] the `for/in` initialization code",
  6405. name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
  6406. object: "[AST_Node] the object that we're looping through"
  6407. },
  6408. _walk: function(visitor) {
  6409. return visitor._visit(this, function(){
  6410. this.init._walk(visitor);
  6411. this.object._walk(visitor);
  6412. this.body._walk(visitor);
  6413. });
  6414. }
  6415. }, AST_IterationStatement);
  6416. var AST_With = DEFNODE("With", "expression", {
  6417. $documentation: "A `with` statement",
  6418. $propdoc: {
  6419. expression: "[AST_Node] the `with` expression"
  6420. },
  6421. _walk: function(visitor) {
  6422. return visitor._visit(this, function(){
  6423. this.expression._walk(visitor);
  6424. this.body._walk(visitor);
  6425. });
  6426. }
  6427. }, AST_StatementWithBody);
  6428. /* -----[ scope and functions ]----- */
  6429. var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
  6430. $documentation: "Base class for all statements introducing a lexical scope",
  6431. $propdoc: {
  6432. directives: "[string*/S] an array of directives declared in this scope",
  6433. variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
  6434. functions: "[Object/S] like `variables`, but only lists function declarations",
  6435. uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
  6436. uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
  6437. parent_scope: "[AST_Scope?/S] link to the parent scope",
  6438. enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
  6439. cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
  6440. },
  6441. }, AST_Block);
  6442. var AST_Toplevel = DEFNODE("Toplevel", "globals", {
  6443. $documentation: "The toplevel scope",
  6444. $propdoc: {
  6445. globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
  6446. },
  6447. wrap_enclose: function(arg_parameter_pairs) {
  6448. var self = this;
  6449. var args = [];
  6450. var parameters = [];
  6451. arg_parameter_pairs.forEach(function(pair) {
  6452. var split = pair.split(":");
  6453. args.push(split[0]);
  6454. parameters.push(split[1]);
  6455. });
  6456. var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
  6457. wrapped_tl = parse(wrapped_tl);
  6458. wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
  6459. if (node instanceof AST_Directive && node.value == "$ORIG") {
  6460. return MAP.splice(self.body);
  6461. }
  6462. }));
  6463. return wrapped_tl;
  6464. },
  6465. wrap_commonjs: function(name, export_all) {
  6466. var self = this;
  6467. var to_export = [];
  6468. if (export_all) {
  6469. self.figure_out_scope();
  6470. self.walk(new TreeWalker(function(node){
  6471. if (node instanceof AST_SymbolDeclaration && node.definition().global) {
  6472. if (!find_if(function(n){ return n.name == node.name }, to_export))
  6473. to_export.push(node);
  6474. }
  6475. }));
  6476. }
  6477. var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
  6478. wrapped_tl = parse(wrapped_tl);
  6479. wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
  6480. if (node instanceof AST_SimpleStatement) {
  6481. node = node.body;
  6482. if (node instanceof AST_String) switch (node.getValue()) {
  6483. case "$ORIG":
  6484. return MAP.splice(self.body);
  6485. case "$EXPORTS":
  6486. var body = [];
  6487. to_export.forEach(function(sym){
  6488. body.push(new AST_SimpleStatement({
  6489. body: new AST_Assign({
  6490. left: new AST_Sub({
  6491. expression: new AST_SymbolRef({ name: "exports" }),
  6492. property: new AST_String({ value: sym.name }),
  6493. }),
  6494. operator: "=",
  6495. right: new AST_SymbolRef(sym),
  6496. }),
  6497. }));
  6498. });
  6499. return MAP.splice(body);
  6500. }
  6501. }
  6502. }));
  6503. return wrapped_tl;
  6504. }
  6505. }, AST_Scope);
  6506. var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
  6507. $documentation: "Base class for functions",
  6508. $propdoc: {
  6509. name: "[AST_SymbolDeclaration?] the name of this function",
  6510. argnames: "[AST_SymbolFunarg*] array of function arguments",
  6511. uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
  6512. },
  6513. _walk: function(visitor) {
  6514. return visitor._visit(this, function(){
  6515. if (this.name) this.name._walk(visitor);
  6516. this.argnames.forEach(function(arg){
  6517. arg._walk(visitor);
  6518. });
  6519. walk_body(this, visitor);
  6520. });
  6521. }
  6522. }, AST_Scope);
  6523. var AST_Accessor = DEFNODE("Accessor", null, {
  6524. $documentation: "A setter/getter function. The `name` property is always null."
  6525. }, AST_Lambda);
  6526. var AST_Function = DEFNODE("Function", null, {
  6527. $documentation: "A function expression"
  6528. }, AST_Lambda);
  6529. var AST_Defun = DEFNODE("Defun", null, {
  6530. $documentation: "A function definition"
  6531. }, AST_Lambda);
  6532. /* -----[ JUMPS ]----- */
  6533. var AST_Jump = DEFNODE("Jump", null, {
  6534. $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
  6535. }, AST_Statement);
  6536. var AST_Exit = DEFNODE("Exit", "value", {
  6537. $documentation: "Base class for “exits” (`return` and `throw`)",
  6538. $propdoc: {
  6539. value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
  6540. },
  6541. _walk: function(visitor) {
  6542. return visitor._visit(this, this.value && function(){
  6543. this.value._walk(visitor);
  6544. });
  6545. }
  6546. }, AST_Jump);
  6547. var AST_Return = DEFNODE("Return", null, {
  6548. $documentation: "A `return` statement"
  6549. }, AST_Exit);
  6550. var AST_Throw = DEFNODE("Throw", null, {
  6551. $documentation: "A `throw` statement"
  6552. }, AST_Exit);
  6553. var AST_LoopControl = DEFNODE("LoopControl", "label", {
  6554. $documentation: "Base class for loop control statements (`break` and `continue`)",
  6555. $propdoc: {
  6556. label: "[AST_LabelRef?] the label, or null if none",
  6557. },
  6558. _walk: function(visitor) {
  6559. return visitor._visit(this, this.label && function(){
  6560. this.label._walk(visitor);
  6561. });
  6562. }
  6563. }, AST_Jump);
  6564. var AST_Break = DEFNODE("Break", null, {
  6565. $documentation: "A `break` statement"
  6566. }, AST_LoopControl);
  6567. var AST_Continue = DEFNODE("Continue", null, {
  6568. $documentation: "A `continue` statement"
  6569. }, AST_LoopControl);
  6570. /* -----[ IF ]----- */
  6571. var AST_If = DEFNODE("If", "condition alternative", {
  6572. $documentation: "A `if` statement",
  6573. $propdoc: {
  6574. condition: "[AST_Node] the `if` condition",
  6575. alternative: "[AST_Statement?] the `else` part, or null if not present"
  6576. },
  6577. _walk: function(visitor) {
  6578. return visitor._visit(this, function(){
  6579. this.condition._walk(visitor);
  6580. this.body._walk(visitor);
  6581. if (this.alternative) this.alternative._walk(visitor);
  6582. });
  6583. }
  6584. }, AST_StatementWithBody);
  6585. /* -----[ SWITCH ]----- */
  6586. var AST_Switch = DEFNODE("Switch", "expression", {
  6587. $documentation: "A `switch` statement",
  6588. $propdoc: {
  6589. expression: "[AST_Node] the `switch` “discriminant”"
  6590. },
  6591. _walk: function(visitor) {
  6592. return visitor._visit(this, function(){
  6593. this.expression._walk(visitor);
  6594. walk_body(this, visitor);
  6595. });
  6596. }
  6597. }, AST_Block);
  6598. var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
  6599. $documentation: "Base class for `switch` branches",
  6600. }, AST_Block);
  6601. var AST_Default = DEFNODE("Default", null, {
  6602. $documentation: "A `default` switch branch",
  6603. }, AST_SwitchBranch);
  6604. var AST_Case = DEFNODE("Case", "expression", {
  6605. $documentation: "A `case` switch branch",
  6606. $propdoc: {
  6607. expression: "[AST_Node] the `case` expression"
  6608. },
  6609. _walk: function(visitor) {
  6610. return visitor._visit(this, function(){
  6611. this.expression._walk(visitor);
  6612. walk_body(this, visitor);
  6613. });
  6614. }
  6615. }, AST_SwitchBranch);
  6616. /* -----[ EXCEPTIONS ]----- */
  6617. var AST_Try = DEFNODE("Try", "bcatch bfinally", {
  6618. $documentation: "A `try` statement",
  6619. $propdoc: {
  6620. bcatch: "[AST_Catch?] the catch block, or null if not present",
  6621. bfinally: "[AST_Finally?] the finally block, or null if not present"
  6622. },
  6623. _walk: function(visitor) {
  6624. return visitor._visit(this, function(){
  6625. walk_body(this, visitor);
  6626. if (this.bcatch) this.bcatch._walk(visitor);
  6627. if (this.bfinally) this.bfinally._walk(visitor);
  6628. });
  6629. }
  6630. }, AST_Block);
  6631. var AST_Catch = DEFNODE("Catch", "argname", {
  6632. $documentation: "A `catch` node; only makes sense as part of a `try` statement",
  6633. $propdoc: {
  6634. argname: "[AST_SymbolCatch] symbol for the exception"
  6635. },
  6636. _walk: function(visitor) {
  6637. return visitor._visit(this, function(){
  6638. this.argname._walk(visitor);
  6639. walk_body(this, visitor);
  6640. });
  6641. }
  6642. }, AST_Block);
  6643. var AST_Finally = DEFNODE("Finally", null, {
  6644. $documentation: "A `finally` node; only makes sense as part of a `try` statement"
  6645. }, AST_Block);
  6646. /* -----[ VAR/CONST ]----- */
  6647. var AST_Definitions = DEFNODE("Definitions", "definitions", {
  6648. $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
  6649. $propdoc: {
  6650. definitions: "[AST_VarDef*] array of variable definitions"
  6651. },
  6652. _walk: function(visitor) {
  6653. return visitor._visit(this, function(){
  6654. this.definitions.forEach(function(def){
  6655. def._walk(visitor);
  6656. });
  6657. });
  6658. }
  6659. }, AST_Statement);
  6660. var AST_Var = DEFNODE("Var", null, {
  6661. $documentation: "A `var` statement"
  6662. }, AST_Definitions);
  6663. var AST_Const = DEFNODE("Const", null, {
  6664. $documentation: "A `const` statement"
  6665. }, AST_Definitions);
  6666. var AST_VarDef = DEFNODE("VarDef", "name value", {
  6667. $documentation: "A variable declaration; only appears in a AST_Definitions node",
  6668. $propdoc: {
  6669. name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
  6670. value: "[AST_Node?] initializer, or null of there's no initializer"
  6671. },
  6672. _walk: function(visitor) {
  6673. return visitor._visit(this, function(){
  6674. this.name._walk(visitor);
  6675. if (this.value) this.value._walk(visitor);
  6676. });
  6677. }
  6678. });
  6679. /* -----[ OTHER ]----- */
  6680. var AST_Call = DEFNODE("Call", "expression args", {
  6681. $documentation: "A function call expression",
  6682. $propdoc: {
  6683. expression: "[AST_Node] expression to invoke as function",
  6684. args: "[AST_Node*] array of arguments"
  6685. },
  6686. _walk: function(visitor) {
  6687. return visitor._visit(this, function(){
  6688. this.expression._walk(visitor);
  6689. this.args.forEach(function(arg){
  6690. arg._walk(visitor);
  6691. });
  6692. });
  6693. }
  6694. });
  6695. var AST_New = DEFNODE("New", null, {
  6696. $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
  6697. }, AST_Call);
  6698. var AST_Seq = DEFNODE("Seq", "car cdr", {
  6699. $documentation: "A sequence expression (two comma-separated expressions)",
  6700. $propdoc: {
  6701. car: "[AST_Node] first element in sequence",
  6702. cdr: "[AST_Node] second element in sequence"
  6703. },
  6704. $cons: function(x, y) {
  6705. var seq = new AST_Seq(x);
  6706. seq.car = x;
  6707. seq.cdr = y;
  6708. return seq;
  6709. },
  6710. $from_array: function(array) {
  6711. if (array.length == 0) return null;
  6712. if (array.length == 1) return array[0].clone();
  6713. var list = null;
  6714. for (var i = array.length; --i >= 0;) {
  6715. list = AST_Seq.cons(array[i], list);
  6716. }
  6717. var p = list;
  6718. while (p) {
  6719. if (p.cdr && !p.cdr.cdr) {
  6720. p.cdr = p.cdr.car;
  6721. break;
  6722. }
  6723. p = p.cdr;
  6724. }
  6725. return list;
  6726. },
  6727. to_array: function() {
  6728. var p = this, a = [];
  6729. while (p) {
  6730. a.push(p.car);
  6731. if (p.cdr && !(p.cdr instanceof AST_Seq)) {
  6732. a.push(p.cdr);
  6733. break;
  6734. }
  6735. p = p.cdr;
  6736. }
  6737. return a;
  6738. },
  6739. add: function(node) {
  6740. var p = this;
  6741. while (p) {
  6742. if (!(p.cdr instanceof AST_Seq)) {
  6743. var cell = AST_Seq.cons(p.cdr, node);
  6744. return p.cdr = cell;
  6745. }
  6746. p = p.cdr;
  6747. }
  6748. },
  6749. _walk: function(visitor) {
  6750. return visitor._visit(this, function(){
  6751. this.car._walk(visitor);
  6752. if (this.cdr) this.cdr._walk(visitor);
  6753. });
  6754. }
  6755. });
  6756. var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
  6757. $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
  6758. $propdoc: {
  6759. expression: "[AST_Node] the “container” expression",
  6760. property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
  6761. }
  6762. });
  6763. var AST_Dot = DEFNODE("Dot", null, {
  6764. $documentation: "A dotted property access expression",
  6765. _walk: function(visitor) {
  6766. return visitor._visit(this, function(){
  6767. this.expression._walk(visitor);
  6768. });
  6769. }
  6770. }, AST_PropAccess);
  6771. var AST_Sub = DEFNODE("Sub", null, {
  6772. $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
  6773. _walk: function(visitor) {
  6774. return visitor._visit(this, function(){
  6775. this.expression._walk(visitor);
  6776. this.property._walk(visitor);
  6777. });
  6778. }
  6779. }, AST_PropAccess);
  6780. var AST_Unary = DEFNODE("Unary", "operator expression", {
  6781. $documentation: "Base class for unary expressions",
  6782. $propdoc: {
  6783. operator: "[string] the operator",
  6784. expression: "[AST_Node] expression that this unary operator applies to"
  6785. },
  6786. _walk: function(visitor) {
  6787. return visitor._visit(this, function(){
  6788. this.expression._walk(visitor);
  6789. });
  6790. }
  6791. });
  6792. var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
  6793. $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
  6794. }, AST_Unary);
  6795. var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
  6796. $documentation: "Unary postfix expression, i.e. `i++`"
  6797. }, AST_Unary);
  6798. var AST_Binary = DEFNODE("Binary", "left operator right", {
  6799. $documentation: "Binary expression, i.e. `a + b`",
  6800. $propdoc: {
  6801. left: "[AST_Node] left-hand side expression",
  6802. operator: "[string] the operator",
  6803. right: "[AST_Node] right-hand side expression"
  6804. },
  6805. _walk: function(visitor) {
  6806. return visitor._visit(this, function(){
  6807. this.left._walk(visitor);
  6808. this.right._walk(visitor);
  6809. });
  6810. }
  6811. });
  6812. var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
  6813. $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
  6814. $propdoc: {
  6815. condition: "[AST_Node]",
  6816. consequent: "[AST_Node]",
  6817. alternative: "[AST_Node]"
  6818. },
  6819. _walk: function(visitor) {
  6820. return visitor._visit(this, function(){
  6821. this.condition._walk(visitor);
  6822. this.consequent._walk(visitor);
  6823. this.alternative._walk(visitor);
  6824. });
  6825. }
  6826. });
  6827. var AST_Assign = DEFNODE("Assign", null, {
  6828. $documentation: "An assignment expression — `a = b + 5`",
  6829. }, AST_Binary);
  6830. /* -----[ LITERALS ]----- */
  6831. var AST_Array = DEFNODE("Array", "elements", {
  6832. $documentation: "An array literal",
  6833. $propdoc: {
  6834. elements: "[AST_Node*] array of elements"
  6835. },
  6836. _walk: function(visitor) {
  6837. return visitor._visit(this, function(){
  6838. this.elements.forEach(function(el){
  6839. el._walk(visitor);
  6840. });
  6841. });
  6842. }
  6843. });
  6844. var AST_Object = DEFNODE("Object", "properties", {
  6845. $documentation: "An object literal",
  6846. $propdoc: {
  6847. properties: "[AST_ObjectProperty*] array of properties"
  6848. },
  6849. _walk: function(visitor) {
  6850. return visitor._visit(this, function(){
  6851. this.properties.forEach(function(prop){
  6852. prop._walk(visitor);
  6853. });
  6854. });
  6855. }
  6856. });
  6857. var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
  6858. $documentation: "Base class for literal object properties",
  6859. $propdoc: {
  6860. key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
  6861. value: "[AST_Node] property value. For setters and getters this is an AST_Function."
  6862. },
  6863. _walk: function(visitor) {
  6864. return visitor._visit(this, function(){
  6865. this.value._walk(visitor);
  6866. });
  6867. }
  6868. });
  6869. var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
  6870. $documentation: "A key: value object property",
  6871. }, AST_ObjectProperty);
  6872. var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
  6873. $documentation: "An object setter property",
  6874. }, AST_ObjectProperty);
  6875. var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
  6876. $documentation: "An object getter property",
  6877. }, AST_ObjectProperty);
  6878. var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
  6879. $propdoc: {
  6880. name: "[string] name of this symbol",
  6881. scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
  6882. thedef: "[SymbolDef/S] the definition of this symbol"
  6883. },
  6884. $documentation: "Base class for all symbols",
  6885. });
  6886. var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
  6887. $documentation: "The name of a property accessor (setter/getter function)"
  6888. }, AST_Symbol);
  6889. var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
  6890. $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
  6891. $propdoc: {
  6892. init: "[AST_Node*/S] array of initializers for this declaration."
  6893. }
  6894. }, AST_Symbol);
  6895. var AST_SymbolVar = DEFNODE("SymbolVar", null, {
  6896. $documentation: "Symbol defining a variable",
  6897. }, AST_SymbolDeclaration);
  6898. var AST_SymbolConst = DEFNODE("SymbolConst", null, {
  6899. $documentation: "A constant declaration"
  6900. }, AST_SymbolDeclaration);
  6901. var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
  6902. $documentation: "Symbol naming a function argument",
  6903. }, AST_SymbolVar);
  6904. var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
  6905. $documentation: "Symbol defining a function",
  6906. }, AST_SymbolDeclaration);
  6907. var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
  6908. $documentation: "Symbol naming a function expression",
  6909. }, AST_SymbolDeclaration);
  6910. var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
  6911. $documentation: "Symbol naming the exception in catch",
  6912. }, AST_SymbolDeclaration);
  6913. var AST_Label = DEFNODE("Label", "references", {
  6914. $documentation: "Symbol naming a label (declaration)",
  6915. $propdoc: {
  6916. references: "[AST_LoopControl*] a list of nodes referring to this label"
  6917. },
  6918. initialize: function() {
  6919. this.references = [];
  6920. this.thedef = this;
  6921. }
  6922. }, AST_Symbol);
  6923. var AST_SymbolRef = DEFNODE("SymbolRef", null, {
  6924. $documentation: "Reference to some symbol (not definition/declaration)",
  6925. }, AST_Symbol);
  6926. var AST_LabelRef = DEFNODE("LabelRef", null, {
  6927. $documentation: "Reference to a label symbol",
  6928. }, AST_Symbol);
  6929. var AST_This = DEFNODE("This", null, {
  6930. $documentation: "The `this` symbol",
  6931. }, AST_Symbol);
  6932. var AST_Constant = DEFNODE("Constant", null, {
  6933. $documentation: "Base class for all constants",
  6934. getValue: function() {
  6935. return this.value;
  6936. }
  6937. });
  6938. var AST_String = DEFNODE("String", "value", {
  6939. $documentation: "A string literal",
  6940. $propdoc: {
  6941. value: "[string] the contents of this string"
  6942. }
  6943. }, AST_Constant);
  6944. var AST_Number = DEFNODE("Number", "value", {
  6945. $documentation: "A number literal",
  6946. $propdoc: {
  6947. value: "[number] the numeric value"
  6948. }
  6949. }, AST_Constant);
  6950. var AST_RegExp = DEFNODE("RegExp", "value", {
  6951. $documentation: "A regexp literal",
  6952. $propdoc: {
  6953. value: "[RegExp] the actual regexp"
  6954. }
  6955. }, AST_Constant);
  6956. var AST_Atom = DEFNODE("Atom", null, {
  6957. $documentation: "Base class for atoms",
  6958. }, AST_Constant);
  6959. var AST_Null = DEFNODE("Null", null, {
  6960. $documentation: "The `null` atom",
  6961. value: null
  6962. }, AST_Atom);
  6963. var AST_NaN = DEFNODE("NaN", null, {
  6964. $documentation: "The impossible value",
  6965. value: 0/0
  6966. }, AST_Atom);
  6967. var AST_Undefined = DEFNODE("Undefined", null, {
  6968. $documentation: "The `undefined` value",
  6969. value: (function(){}())
  6970. }, AST_Atom);
  6971. var AST_Hole = DEFNODE("Hole", null, {
  6972. $documentation: "A hole in an array",
  6973. value: (function(){}())
  6974. }, AST_Atom);
  6975. var AST_Infinity = DEFNODE("Infinity", null, {
  6976. $documentation: "The `Infinity` value",
  6977. value: 1/0
  6978. }, AST_Atom);
  6979. var AST_Boolean = DEFNODE("Boolean", null, {
  6980. $documentation: "Base class for booleans",
  6981. }, AST_Atom);
  6982. var AST_False = DEFNODE("False", null, {
  6983. $documentation: "The `false` atom",
  6984. value: false
  6985. }, AST_Boolean);
  6986. var AST_True = DEFNODE("True", null, {
  6987. $documentation: "The `true` atom",
  6988. value: true
  6989. }, AST_Boolean);
  6990. /* -----[ TreeWalker ]----- */
  6991. function TreeWalker(callback) {
  6992. this.visit = callback;
  6993. this.stack = [];
  6994. };
  6995. TreeWalker.prototype = {
  6996. _visit: function(node, descend) {
  6997. this.stack.push(node);
  6998. var ret = this.visit(node, descend ? function(){
  6999. descend.call(node);
  7000. } : noop);
  7001. if (!ret && descend) {
  7002. descend.call(node);
  7003. }
  7004. this.stack.pop();
  7005. return ret;
  7006. },
  7007. parent: function(n) {
  7008. return this.stack[this.stack.length - 2 - (n || 0)];
  7009. },
  7010. push: function (node) {
  7011. this.stack.push(node);
  7012. },
  7013. pop: function() {
  7014. return this.stack.pop();
  7015. },
  7016. self: function() {
  7017. return this.stack[this.stack.length - 1];
  7018. },
  7019. find_parent: function(type) {
  7020. var stack = this.stack;
  7021. for (var i = stack.length; --i >= 0;) {
  7022. var x = stack[i];
  7023. if (x instanceof type) return x;
  7024. }
  7025. },
  7026. has_directive: function(type) {
  7027. return this.find_parent(AST_Scope).has_directive(type);
  7028. },
  7029. in_boolean_context: function() {
  7030. var stack = this.stack;
  7031. var i = stack.length, self = stack[--i];
  7032. while (i > 0) {
  7033. var p = stack[--i];
  7034. if ((p instanceof AST_If && p.condition === self) ||
  7035. (p instanceof AST_Conditional && p.condition === self) ||
  7036. (p instanceof AST_DWLoop && p.condition === self) ||
  7037. (p instanceof AST_For && p.condition === self) ||
  7038. (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
  7039. {
  7040. return true;
  7041. }
  7042. if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
  7043. return false;
  7044. self = p;
  7045. }
  7046. },
  7047. loopcontrol_target: function(label) {
  7048. var stack = this.stack;
  7049. if (label) for (var i = stack.length; --i >= 0;) {
  7050. var x = stack[i];
  7051. if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
  7052. return x.body;
  7053. }
  7054. } else for (var i = stack.length; --i >= 0;) {
  7055. var x = stack[i];
  7056. if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
  7057. return x;
  7058. }
  7059. }
  7060. };
  7061. /***********************************************************************
  7062. A JavaScript tokenizer / parser / beautifier / compressor.
  7063. https://github.com/mishoo/UglifyJS2
  7064. -------------------------------- (C) ---------------------------------
  7065. Author: Mihai Bazon
  7066. <mihai.bazon@gmail.com>
  7067. http://mihai.bazon.net/blog
  7068. Distributed under the BSD license:
  7069. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  7070. Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
  7071. Redistribution and use in source and binary forms, with or without
  7072. modification, are permitted provided that the following conditions
  7073. are met:
  7074. * Redistributions of source code must retain the above
  7075. copyright notice, this list of conditions and the following
  7076. disclaimer.
  7077. * Redistributions in binary form must reproduce the above
  7078. copyright notice, this list of conditions and the following
  7079. disclaimer in the documentation and/or other materials
  7080. provided with the distribution.
  7081. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  7082. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  7083. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  7084. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  7085. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  7086. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  7087. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  7088. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  7089. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  7090. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  7091. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  7092. SUCH DAMAGE.
  7093. ***********************************************************************/
  7094. "use strict";
  7095. var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
  7096. var KEYWORDS_ATOM = 'false null true';
  7097. var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile'
  7098. + " " + KEYWORDS_ATOM + " " + KEYWORDS;
  7099. var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
  7100. KEYWORDS = makePredicate(KEYWORDS);
  7101. RESERVED_WORDS = makePredicate(RESERVED_WORDS);
  7102. KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
  7103. KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
  7104. var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
  7105. var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
  7106. var RE_OCT_NUMBER = /^0[0-7]+$/;
  7107. var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
  7108. var OPERATORS = makePredicate([
  7109. "in",
  7110. "instanceof",
  7111. "typeof",
  7112. "new",
  7113. "void",
  7114. "delete",
  7115. "++",
  7116. "--",
  7117. "+",
  7118. "-",
  7119. "!",
  7120. "~",
  7121. "&",
  7122. "|",
  7123. "^",
  7124. "*",
  7125. "/",
  7126. "%",
  7127. ">>",
  7128. "<<",
  7129. ">>>",
  7130. "<",
  7131. ">",
  7132. "<=",
  7133. ">=",
  7134. "==",
  7135. "===",
  7136. "!=",
  7137. "!==",
  7138. "?",
  7139. "=",
  7140. "+=",
  7141. "-=",
  7142. "/=",
  7143. "*=",
  7144. "%=",
  7145. ">>=",
  7146. "<<=",
  7147. ">>>=",
  7148. "|=",
  7149. "^=",
  7150. "&=",
  7151. "&&",
  7152. "||"
  7153. ]);
  7154. var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
  7155. var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
  7156. var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
  7157. var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
  7158. /* -----[ Tokenizer ]----- */
  7159. // regexps adapted from http://xregexp.com/plugins/#unicode
  7160. var UNICODE = {
  7161. letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\
  7162. non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
  7163. space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
  7164. connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
  7165. };
  7166. function is_letter(code) {
  7167. return (code >= 97 && code <= 122)
  7168. || (code >= 65 && code <= 90)
  7169. || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
  7170. };
  7171. function is_digit(code) {
  7172. return code >= 48 && code <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
  7173. };
  7174. function is_alphanumeric_char(code) {
  7175. return is_digit(code) || is_letter(code);
  7176. };
  7177. function is_unicode_combining_mark(ch) {
  7178. return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
  7179. };
  7180. function is_unicode_connector_punctuation(ch) {
  7181. return UNICODE.connector_punctuation.test(ch);
  7182. };
  7183. function is_identifier(name) {
  7184. return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
  7185. };
  7186. function is_identifier_start(code) {
  7187. return code == 36 || code == 95 || is_letter(code);
  7188. };
  7189. function is_identifier_char(ch) {
  7190. var code = ch.charCodeAt(0);
  7191. return is_identifier_start(code)
  7192. || is_digit(code)
  7193. || code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
  7194. || code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
  7195. || is_unicode_combining_mark(ch)
  7196. || is_unicode_connector_punctuation(ch)
  7197. ;
  7198. };
  7199. function is_identifier_string(str){
  7200. var i = str.length;
  7201. if (i == 0) return false;
  7202. if (!is_identifier_start(str.charCodeAt(0))) return false;
  7203. while (--i >= 0) {
  7204. if (!is_identifier_char(str.charAt(i)))
  7205. return false;
  7206. }
  7207. return true;
  7208. };
  7209. function parse_js_number(num) {
  7210. if (RE_HEX_NUMBER.test(num)) {
  7211. return parseInt(num.substr(2), 16);
  7212. } else if (RE_OCT_NUMBER.test(num)) {
  7213. return parseInt(num.substr(1), 8);
  7214. } else if (RE_DEC_NUMBER.test(num)) {
  7215. return parseFloat(num);
  7216. }
  7217. };
  7218. function JS_Parse_Error(message, line, col, pos) {
  7219. this.message = message;
  7220. this.line = line;
  7221. this.col = col;
  7222. this.pos = pos;
  7223. this.stack = new Error().stack;
  7224. };
  7225. JS_Parse_Error.prototype.toString = function() {
  7226. return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
  7227. };
  7228. function js_error(message, filename, line, col, pos) {
  7229. throw new JS_Parse_Error(message, line, col, pos);
  7230. };
  7231. function is_token(token, type, val) {
  7232. return token.type == type && (val == null || token.value == val);
  7233. };
  7234. var EX_EOF = {};
  7235. function tokenizer($TEXT, filename, html5_comments) {
  7236. var S = {
  7237. text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''),
  7238. filename : filename,
  7239. pos : 0,
  7240. tokpos : 0,
  7241. line : 1,
  7242. tokline : 0,
  7243. col : 0,
  7244. tokcol : 0,
  7245. newline_before : false,
  7246. regex_allowed : false,
  7247. comments_before : []
  7248. };
  7249. function peek() { return S.text.charAt(S.pos); };
  7250. function next(signal_eof, in_string) {
  7251. var ch = S.text.charAt(S.pos++);
  7252. if (signal_eof && !ch)
  7253. throw EX_EOF;
  7254. if (ch == "\n") {
  7255. S.newline_before = S.newline_before || !in_string;
  7256. ++S.line;
  7257. S.col = 0;
  7258. } else {
  7259. ++S.col;
  7260. }
  7261. return ch;
  7262. };
  7263. function forward(i) {
  7264. while (i-- > 0) next();
  7265. };
  7266. function looking_at(str) {
  7267. return S.text.substr(S.pos, str.length) == str;
  7268. };
  7269. function find(what, signal_eof) {
  7270. var pos = S.text.indexOf(what, S.pos);
  7271. if (signal_eof && pos == -1) throw EX_EOF;
  7272. return pos;
  7273. };
  7274. function start_token() {
  7275. S.tokline = S.line;
  7276. S.tokcol = S.col;
  7277. S.tokpos = S.pos;
  7278. };
  7279. var prev_was_dot = false;
  7280. function token(type, value, is_comment) {
  7281. S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
  7282. (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
  7283. (type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
  7284. prev_was_dot = (type == "punc" && value == ".");
  7285. var ret = {
  7286. type : type,
  7287. value : value,
  7288. line : S.tokline,
  7289. col : S.tokcol,
  7290. pos : S.tokpos,
  7291. endpos : S.pos,
  7292. nlb : S.newline_before,
  7293. file : filename
  7294. };
  7295. if (!is_comment) {
  7296. ret.comments_before = S.comments_before;
  7297. S.comments_before = [];
  7298. // make note of any newlines in the comments that came before
  7299. for (var i = 0, len = ret.comments_before.length; i < len; i++) {
  7300. ret.nlb = ret.nlb || ret.comments_before[i].nlb;
  7301. }
  7302. }
  7303. S.newline_before = false;
  7304. return new AST_Token(ret);
  7305. };
  7306. function skip_whitespace() {
  7307. while (WHITESPACE_CHARS(peek()))
  7308. next();
  7309. };
  7310. function read_while(pred) {
  7311. var ret = "", ch, i = 0;
  7312. while ((ch = peek()) && pred(ch, i++))
  7313. ret += next();
  7314. return ret;
  7315. };
  7316. function parse_error(err) {
  7317. js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
  7318. };
  7319. function read_num(prefix) {
  7320. var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
  7321. var num = read_while(function(ch, i){
  7322. var code = ch.charCodeAt(0);
  7323. switch (code) {
  7324. case 120: case 88: // xX
  7325. return has_x ? false : (has_x = true);
  7326. case 101: case 69: // eE
  7327. return has_x ? true : has_e ? false : (has_e = after_e = true);
  7328. case 45: // -
  7329. return after_e || (i == 0 && !prefix);
  7330. case 43: // +
  7331. return after_e;
  7332. case (after_e = false, 46): // .
  7333. return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
  7334. }
  7335. return is_alphanumeric_char(code);
  7336. });
  7337. if (prefix) num = prefix + num;
  7338. var valid = parse_js_number(num);
  7339. if (!isNaN(valid)) {
  7340. return token("num", valid);
  7341. } else {
  7342. parse_error("Invalid syntax: " + num);
  7343. }
  7344. };
  7345. function read_escaped_char(in_string) {
  7346. var ch = next(true, in_string);
  7347. switch (ch.charCodeAt(0)) {
  7348. case 110 : return "\n";
  7349. case 114 : return "\r";
  7350. case 116 : return "\t";
  7351. case 98 : return "\b";
  7352. case 118 : return "\u000b"; // \v
  7353. case 102 : return "\f";
  7354. case 48 : return "\0";
  7355. case 120 : return String.fromCharCode(hex_bytes(2)); // \x
  7356. case 117 : return String.fromCharCode(hex_bytes(4)); // \u
  7357. case 10 : return ""; // newline
  7358. default : return ch;
  7359. }
  7360. };
  7361. function hex_bytes(n) {
  7362. var num = 0;
  7363. for (; n > 0; --n) {
  7364. var digit = parseInt(next(true), 16);
  7365. if (isNaN(digit))
  7366. parse_error("Invalid hex-character pattern in string");
  7367. num = (num << 4) | digit;
  7368. }
  7369. return num;
  7370. };
  7371. var read_string = with_eof_error("Unterminated string constant", function(){
  7372. var quote = next(), ret = "";
  7373. for (;;) {
  7374. var ch = next(true);
  7375. if (ch == "\\") {
  7376. // read OctalEscapeSequence (XXX: deprecated if "strict mode")
  7377. // https://github.com/mishoo/UglifyJS/issues/178
  7378. var octal_len = 0, first = null;
  7379. ch = read_while(function(ch){
  7380. if (ch >= "0" && ch <= "7") {
  7381. if (!first) {
  7382. first = ch;
  7383. return ++octal_len;
  7384. }
  7385. else if (first <= "3" && octal_len <= 2) return ++octal_len;
  7386. else if (first >= "4" && octal_len <= 1) return ++octal_len;
  7387. }
  7388. return false;
  7389. });
  7390. if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
  7391. else ch = read_escaped_char(true);
  7392. }
  7393. else if (ch == quote) break;
  7394. ret += ch;
  7395. }
  7396. return token("string", ret);
  7397. });
  7398. function skip_line_comment(type) {
  7399. var regex_allowed = S.regex_allowed;
  7400. var i = find("\n"), ret;
  7401. if (i == -1) {
  7402. ret = S.text.substr(S.pos);
  7403. S.pos = S.text.length;
  7404. } else {
  7405. ret = S.text.substring(S.pos, i);
  7406. S.pos = i;
  7407. }
  7408. S.comments_before.push(token(type, ret, true));
  7409. S.regex_allowed = regex_allowed;
  7410. return next_token();
  7411. };
  7412. var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
  7413. var regex_allowed = S.regex_allowed;
  7414. var i = find("*/", true);
  7415. var text = S.text.substring(S.pos, i);
  7416. var a = text.split("\n"), n = a.length;
  7417. // update stream position
  7418. S.pos = i + 2;
  7419. S.line += n - 1;
  7420. if (n > 1) S.col = a[n - 1].length;
  7421. else S.col += a[n - 1].length;
  7422. S.col += 2;
  7423. var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
  7424. S.comments_before.push(token("comment2", text, true));
  7425. S.regex_allowed = regex_allowed;
  7426. S.newline_before = nlb;
  7427. return next_token();
  7428. });
  7429. function read_name() {
  7430. var backslash = false, name = "", ch, escaped = false, hex;
  7431. while ((ch = peek()) != null) {
  7432. if (!backslash) {
  7433. if (ch == "\\") escaped = backslash = true, next();
  7434. else if (is_identifier_char(ch)) name += next();
  7435. else break;
  7436. }
  7437. else {
  7438. if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
  7439. ch = read_escaped_char();
  7440. if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
  7441. name += ch;
  7442. backslash = false;
  7443. }
  7444. }
  7445. if (KEYWORDS(name) && escaped) {
  7446. hex = name.charCodeAt(0).toString(16).toUpperCase();
  7447. name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
  7448. }
  7449. return name;
  7450. };
  7451. var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
  7452. var prev_backslash = false, ch, in_class = false;
  7453. while ((ch = next(true))) if (prev_backslash) {
  7454. regexp += "\\" + ch;
  7455. prev_backslash = false;
  7456. } else if (ch == "[") {
  7457. in_class = true;
  7458. regexp += ch;
  7459. } else if (ch == "]" && in_class) {
  7460. in_class = false;
  7461. regexp += ch;
  7462. } else if (ch == "/" && !in_class) {
  7463. break;
  7464. } else if (ch == "\\") {
  7465. prev_backslash = true;
  7466. } else {
  7467. regexp += ch;
  7468. }
  7469. var mods = read_name();
  7470. return token("regexp", new RegExp(regexp, mods));
  7471. });
  7472. function read_operator(prefix) {
  7473. function grow(op) {
  7474. if (!peek()) return op;
  7475. var bigger = op + peek();
  7476. if (OPERATORS(bigger)) {
  7477. next();
  7478. return grow(bigger);
  7479. } else {
  7480. return op;
  7481. }
  7482. };
  7483. return token("operator", grow(prefix || next()));
  7484. };
  7485. function handle_slash() {
  7486. next();
  7487. switch (peek()) {
  7488. case "/":
  7489. next();
  7490. return skip_line_comment("comment1");
  7491. case "*":
  7492. next();
  7493. return skip_multiline_comment();
  7494. }
  7495. return S.regex_allowed ? read_regexp("") : read_operator("/");
  7496. };
  7497. function handle_dot() {
  7498. next();
  7499. return is_digit(peek().charCodeAt(0))
  7500. ? read_num(".")
  7501. : token("punc", ".");
  7502. };
  7503. function read_word() {
  7504. var word = read_name();
  7505. if (prev_was_dot) return token("name", word);
  7506. return KEYWORDS_ATOM(word) ? token("atom", word)
  7507. : !KEYWORDS(word) ? token("name", word)
  7508. : OPERATORS(word) ? token("operator", word)
  7509. : token("keyword", word);
  7510. };
  7511. function with_eof_error(eof_error, cont) {
  7512. return function(x) {
  7513. try {
  7514. return cont(x);
  7515. } catch(ex) {
  7516. if (ex === EX_EOF) parse_error(eof_error);
  7517. else throw ex;
  7518. }
  7519. };
  7520. };
  7521. function next_token(force_regexp) {
  7522. if (force_regexp != null)
  7523. return read_regexp(force_regexp);
  7524. skip_whitespace();
  7525. start_token();
  7526. if (html5_comments) {
  7527. if (looking_at("<!--")) {
  7528. forward(4);
  7529. return skip_line_comment("comment3");
  7530. }
  7531. if (looking_at("-->") && S.newline_before) {
  7532. forward(3);
  7533. return skip_line_comment("comment4");
  7534. }
  7535. }
  7536. var ch = peek();
  7537. if (!ch) return token("eof");
  7538. var code = ch.charCodeAt(0);
  7539. switch (code) {
  7540. case 34: case 39: return read_string();
  7541. case 46: return handle_dot();
  7542. case 47: return handle_slash();
  7543. }
  7544. if (is_digit(code)) return read_num();
  7545. if (PUNC_CHARS(ch)) return token("punc", next());
  7546. if (OPERATOR_CHARS(ch)) return read_operator();
  7547. if (code == 92 || is_identifier_start(code)) return read_word();
  7548. parse_error("Unexpected character '" + ch + "'");
  7549. };
  7550. next_token.context = function(nc) {
  7551. if (nc) S = nc;
  7552. return S;
  7553. };
  7554. return next_token;
  7555. };
  7556. /* -----[ Parser (constants) ]----- */
  7557. var UNARY_PREFIX = makePredicate([
  7558. "typeof",
  7559. "void",
  7560. "delete",
  7561. "--",
  7562. "++",
  7563. "!",
  7564. "~",
  7565. "-",
  7566. "+"
  7567. ]);
  7568. var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
  7569. var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
  7570. var PRECEDENCE = (function(a, ret){
  7571. for (var i = 0; i < a.length; ++i) {
  7572. var b = a[i];
  7573. for (var j = 0; j < b.length; ++j) {
  7574. ret[b[j]] = i + 1;
  7575. }
  7576. }
  7577. return ret;
  7578. })(
  7579. [
  7580. ["||"],
  7581. ["&&"],
  7582. ["|"],
  7583. ["^"],
  7584. ["&"],
  7585. ["==", "===", "!=", "!=="],
  7586. ["<", ">", "<=", ">=", "in", "instanceof"],
  7587. [">>", "<<", ">>>"],
  7588. ["+", "-"],
  7589. ["*", "/", "%"]
  7590. ],
  7591. {}
  7592. );
  7593. var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
  7594. var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
  7595. /* -----[ Parser ]----- */
  7596. function parse($TEXT, options) {
  7597. options = defaults(options, {
  7598. strict : false,
  7599. filename : null,
  7600. toplevel : null,
  7601. expression : false,
  7602. html5_comments : true,
  7603. });
  7604. var S = {
  7605. input : (typeof $TEXT == "string"
  7606. ? tokenizer($TEXT, options.filename,
  7607. options.html5_comments)
  7608. : $TEXT),
  7609. token : null,
  7610. prev : null,
  7611. peeked : null,
  7612. in_function : 0,
  7613. in_directives : true,
  7614. in_loop : 0,
  7615. labels : []
  7616. };
  7617. S.token = next();
  7618. function is(type, value) {
  7619. return is_token(S.token, type, value);
  7620. };
  7621. function peek() { return S.peeked || (S.peeked = S.input()); };
  7622. function next() {
  7623. S.prev = S.token;
  7624. if (S.peeked) {
  7625. S.token = S.peeked;
  7626. S.peeked = null;
  7627. } else {
  7628. S.token = S.input();
  7629. }
  7630. S.in_directives = S.in_directives && (
  7631. S.token.type == "string" || is("punc", ";")
  7632. );
  7633. return S.token;
  7634. };
  7635. function prev() {
  7636. return S.prev;
  7637. };
  7638. function croak(msg, line, col, pos) {
  7639. var ctx = S.input.context();
  7640. js_error(msg,
  7641. ctx.filename,
  7642. line != null ? line : ctx.tokline,
  7643. col != null ? col : ctx.tokcol,
  7644. pos != null ? pos : ctx.tokpos);
  7645. };
  7646. function token_error(token, msg) {
  7647. croak(msg, token.line, token.col);
  7648. };
  7649. function unexpected(token) {
  7650. if (token == null)
  7651. token = S.token;
  7652. token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
  7653. };
  7654. function expect_token(type, val) {
  7655. if (is(type, val)) {
  7656. return next();
  7657. }
  7658. token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
  7659. };
  7660. function expect(punc) { return expect_token("punc", punc); };
  7661. function can_insert_semicolon() {
  7662. return !options.strict && (
  7663. S.token.nlb || is("eof") || is("punc", "}")
  7664. );
  7665. };
  7666. function semicolon() {
  7667. if (is("punc", ";")) next();
  7668. else if (!can_insert_semicolon()) unexpected();
  7669. };
  7670. function parenthesised() {
  7671. expect("(");
  7672. var exp = expression(true);
  7673. expect(")");
  7674. return exp;
  7675. };
  7676. function embed_tokens(parser) {
  7677. return function() {
  7678. var start = S.token;
  7679. var expr = parser();
  7680. var end = prev();
  7681. expr.start = start;
  7682. expr.end = end;
  7683. return expr;
  7684. };
  7685. };
  7686. function handle_regexp() {
  7687. if (is("operator", "/") || is("operator", "/=")) {
  7688. S.peeked = null;
  7689. S.token = S.input(S.token.value.substr(1)); // force regexp
  7690. }
  7691. };
  7692. var statement = embed_tokens(function() {
  7693. var tmp;
  7694. handle_regexp();
  7695. switch (S.token.type) {
  7696. case "string":
  7697. var dir = S.in_directives, stat = simple_statement();
  7698. // XXXv2: decide how to fix directives
  7699. if (dir && stat.body instanceof AST_String && !is("punc", ","))
  7700. return new AST_Directive({ value: stat.body.value });
  7701. return stat;
  7702. case "num":
  7703. case "regexp":
  7704. case "operator":
  7705. case "atom":
  7706. return simple_statement();
  7707. case "name":
  7708. return is_token(peek(), "punc", ":")
  7709. ? labeled_statement()
  7710. : simple_statement();
  7711. case "punc":
  7712. switch (S.token.value) {
  7713. case "{":
  7714. return new AST_BlockStatement({
  7715. start : S.token,
  7716. body : block_(),
  7717. end : prev()
  7718. });
  7719. case "[":
  7720. case "(":
  7721. return simple_statement();
  7722. case ";":
  7723. next();
  7724. return new AST_EmptyStatement();
  7725. default:
  7726. unexpected();
  7727. }
  7728. case "keyword":
  7729. switch (tmp = S.token.value, next(), tmp) {
  7730. case "break":
  7731. return break_cont(AST_Break);
  7732. case "continue":
  7733. return break_cont(AST_Continue);
  7734. case "debugger":
  7735. semicolon();
  7736. return new AST_Debugger();
  7737. case "do":
  7738. return new AST_Do({
  7739. body : in_loop(statement),
  7740. condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp)
  7741. });
  7742. case "while":
  7743. return new AST_While({
  7744. condition : parenthesised(),
  7745. body : in_loop(statement)
  7746. });
  7747. case "for":
  7748. return for_();
  7749. case "function":
  7750. return function_(AST_Defun);
  7751. case "if":
  7752. return if_();
  7753. case "return":
  7754. if (S.in_function == 0)
  7755. croak("'return' outside of function");
  7756. return new AST_Return({
  7757. value: ( is("punc", ";")
  7758. ? (next(), null)
  7759. : can_insert_semicolon()
  7760. ? null
  7761. : (tmp = expression(true), semicolon(), tmp) )
  7762. });
  7763. case "switch":
  7764. return new AST_Switch({
  7765. expression : parenthesised(),
  7766. body : in_loop(switch_body_)
  7767. });
  7768. case "throw":
  7769. if (S.token.nlb)
  7770. croak("Illegal newline after 'throw'");
  7771. return new AST_Throw({
  7772. value: (tmp = expression(true), semicolon(), tmp)
  7773. });
  7774. case "try":
  7775. return try_();
  7776. case "var":
  7777. return tmp = var_(), semicolon(), tmp;
  7778. case "const":
  7779. return tmp = const_(), semicolon(), tmp;
  7780. case "with":
  7781. return new AST_With({
  7782. expression : parenthesised(),
  7783. body : statement()
  7784. });
  7785. default:
  7786. unexpected();
  7787. }
  7788. }
  7789. });
  7790. function labeled_statement() {
  7791. var label = as_symbol(AST_Label);
  7792. if (find_if(function(l){ return l.name == label.name }, S.labels)) {
  7793. // ECMA-262, 12.12: An ECMAScript program is considered
  7794. // syntactically incorrect if it contains a
  7795. // LabelledStatement that is enclosed by a
  7796. // LabelledStatement with the same Identifier as label.
  7797. croak("Label " + label.name + " defined twice");
  7798. }
  7799. expect(":");
  7800. S.labels.push(label);
  7801. var stat = statement();
  7802. S.labels.pop();
  7803. if (!(stat instanceof AST_IterationStatement)) {
  7804. // check for `continue` that refers to this label.
  7805. // those should be reported as syntax errors.
  7806. // https://github.com/mishoo/UglifyJS2/issues/287
  7807. label.references.forEach(function(ref){
  7808. if (ref instanceof AST_Continue) {
  7809. ref = ref.label.start;
  7810. croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
  7811. ref.line, ref.col, ref.pos);
  7812. }
  7813. });
  7814. }
  7815. return new AST_LabeledStatement({ body: stat, label: label });
  7816. };
  7817. function simple_statement(tmp) {
  7818. return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
  7819. };
  7820. function break_cont(type) {
  7821. var label = null, ldef;
  7822. if (!can_insert_semicolon()) {
  7823. label = as_symbol(AST_LabelRef, true);
  7824. }
  7825. if (label != null) {
  7826. ldef = find_if(function(l){ return l.name == label.name }, S.labels);
  7827. if (!ldef)
  7828. croak("Undefined label " + label.name);
  7829. label.thedef = ldef;
  7830. }
  7831. else if (S.in_loop == 0)
  7832. croak(type.TYPE + " not inside a loop or switch");
  7833. semicolon();
  7834. var stat = new type({ label: label });
  7835. if (ldef) ldef.references.push(stat);
  7836. return stat;
  7837. };
  7838. function for_() {
  7839. expect("(");
  7840. var init = null;
  7841. if (!is("punc", ";")) {
  7842. init = is("keyword", "var")
  7843. ? (next(), var_(true))
  7844. : expression(true, true);
  7845. if (is("operator", "in")) {
  7846. if (init instanceof AST_Var && init.definitions.length > 1)
  7847. croak("Only one variable declaration allowed in for..in loop");
  7848. next();
  7849. return for_in(init);
  7850. }
  7851. }
  7852. return regular_for(init);
  7853. };
  7854. function regular_for(init) {
  7855. expect(";");
  7856. var test = is("punc", ";") ? null : expression(true);
  7857. expect(";");
  7858. var step = is("punc", ")") ? null : expression(true);
  7859. expect(")");
  7860. return new AST_For({
  7861. init : init,
  7862. condition : test,
  7863. step : step,
  7864. body : in_loop(statement)
  7865. });
  7866. };
  7867. function for_in(init) {
  7868. var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
  7869. var obj = expression(true);
  7870. expect(")");
  7871. return new AST_ForIn({
  7872. init : init,
  7873. name : lhs,
  7874. object : obj,
  7875. body : in_loop(statement)
  7876. });
  7877. };
  7878. var function_ = function(ctor) {
  7879. var in_statement = ctor === AST_Defun;
  7880. var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
  7881. if (in_statement && !name)
  7882. unexpected();
  7883. expect("(");
  7884. return new ctor({
  7885. name: name,
  7886. argnames: (function(first, a){
  7887. while (!is("punc", ")")) {
  7888. if (first) first = false; else expect(",");
  7889. a.push(as_symbol(AST_SymbolFunarg));
  7890. }
  7891. next();
  7892. return a;
  7893. })(true, []),
  7894. body: (function(loop, labels){
  7895. ++S.in_function;
  7896. S.in_directives = true;
  7897. S.in_loop = 0;
  7898. S.labels = [];
  7899. var a = block_();
  7900. --S.in_function;
  7901. S.in_loop = loop;
  7902. S.labels = labels;
  7903. return a;
  7904. })(S.in_loop, S.labels)
  7905. });
  7906. };
  7907. function if_() {
  7908. var cond = parenthesised(), body = statement(), belse = null;
  7909. if (is("keyword", "else")) {
  7910. next();
  7911. belse = statement();
  7912. }
  7913. return new AST_If({
  7914. condition : cond,
  7915. body : body,
  7916. alternative : belse
  7917. });
  7918. };
  7919. function block_() {
  7920. expect("{");
  7921. var a = [];
  7922. while (!is("punc", "}")) {
  7923. if (is("eof")) unexpected();
  7924. a.push(statement());
  7925. }
  7926. next();
  7927. return a;
  7928. };
  7929. function switch_body_() {
  7930. expect("{");
  7931. var a = [], cur = null, branch = null, tmp;
  7932. while (!is("punc", "}")) {
  7933. if (is("eof")) unexpected();
  7934. if (is("keyword", "case")) {
  7935. if (branch) branch.end = prev();
  7936. cur = [];
  7937. branch = new AST_Case({
  7938. start : (tmp = S.token, next(), tmp),
  7939. expression : expression(true),
  7940. body : cur
  7941. });
  7942. a.push(branch);
  7943. expect(":");
  7944. }
  7945. else if (is("keyword", "default")) {
  7946. if (branch) branch.end = prev();
  7947. cur = [];
  7948. branch = new AST_Default({
  7949. start : (tmp = S.token, next(), expect(":"), tmp),
  7950. body : cur
  7951. });
  7952. a.push(branch);
  7953. }
  7954. else {
  7955. if (!cur) unexpected();
  7956. cur.push(statement());
  7957. }
  7958. }
  7959. if (branch) branch.end = prev();
  7960. next();
  7961. return a;
  7962. };
  7963. function try_() {
  7964. var body = block_(), bcatch = null, bfinally = null;
  7965. if (is("keyword", "catch")) {
  7966. var start = S.token;
  7967. next();
  7968. expect("(");
  7969. var name = as_symbol(AST_SymbolCatch);
  7970. expect(")");
  7971. bcatch = new AST_Catch({
  7972. start : start,
  7973. argname : name,
  7974. body : block_(),
  7975. end : prev()
  7976. });
  7977. }
  7978. if (is("keyword", "finally")) {
  7979. var start = S.token;
  7980. next();
  7981. bfinally = new AST_Finally({
  7982. start : start,
  7983. body : block_(),
  7984. end : prev()
  7985. });
  7986. }
  7987. if (!bcatch && !bfinally)
  7988. croak("Missing catch/finally blocks");
  7989. return new AST_Try({
  7990. body : body,
  7991. bcatch : bcatch,
  7992. bfinally : bfinally
  7993. });
  7994. };
  7995. function vardefs(no_in, in_const) {
  7996. var a = [];
  7997. for (;;) {
  7998. a.push(new AST_VarDef({
  7999. start : S.token,
  8000. name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
  8001. value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
  8002. end : prev()
  8003. }));
  8004. if (!is("punc", ","))
  8005. break;
  8006. next();
  8007. }
  8008. return a;
  8009. };
  8010. var var_ = function(no_in) {
  8011. return new AST_Var({
  8012. start : prev(),
  8013. definitions : vardefs(no_in, false),
  8014. end : prev()
  8015. });
  8016. };
  8017. var const_ = function() {
  8018. return new AST_Const({
  8019. start : prev(),
  8020. definitions : vardefs(false, true),
  8021. end : prev()
  8022. });
  8023. };
  8024. var new_ = function() {
  8025. var start = S.token;
  8026. expect_token("operator", "new");
  8027. var newexp = expr_atom(false), args;
  8028. if (is("punc", "(")) {
  8029. next();
  8030. args = expr_list(")");
  8031. } else {
  8032. args = [];
  8033. }
  8034. return subscripts(new AST_New({
  8035. start : start,
  8036. expression : newexp,
  8037. args : args,
  8038. end : prev()
  8039. }), true);
  8040. };
  8041. function as_atom_node() {
  8042. var tok = S.token, ret;
  8043. switch (tok.type) {
  8044. case "name":
  8045. case "keyword":
  8046. ret = _make_symbol(AST_SymbolRef);
  8047. break;
  8048. case "num":
  8049. ret = new AST_Number({ start: tok, end: tok, value: tok.value });
  8050. break;
  8051. case "string":
  8052. ret = new AST_String({ start: tok, end: tok, value: tok.value });
  8053. break;
  8054. case "regexp":
  8055. ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
  8056. break;
  8057. case "atom":
  8058. switch (tok.value) {
  8059. case "false":
  8060. ret = new AST_False({ start: tok, end: tok });
  8061. break;
  8062. case "true":
  8063. ret = new AST_True({ start: tok, end: tok });
  8064. break;
  8065. case "null":
  8066. ret = new AST_Null({ start: tok, end: tok });
  8067. break;
  8068. }
  8069. break;
  8070. }
  8071. next();
  8072. return ret;
  8073. };
  8074. var expr_atom = function(allow_calls) {
  8075. if (is("operator", "new")) {
  8076. return new_();
  8077. }
  8078. var start = S.token;
  8079. if (is("punc")) {
  8080. switch (start.value) {
  8081. case "(":
  8082. next();
  8083. var ex = expression(true);
  8084. ex.start = start;
  8085. ex.end = S.token;
  8086. expect(")");
  8087. return subscripts(ex, allow_calls);
  8088. case "[":
  8089. return subscripts(array_(), allow_calls);
  8090. case "{":
  8091. return subscripts(object_(), allow_calls);
  8092. }
  8093. unexpected();
  8094. }
  8095. if (is("keyword", "function")) {
  8096. next();
  8097. var func = function_(AST_Function);
  8098. func.start = start;
  8099. func.end = prev();
  8100. return subscripts(func, allow_calls);
  8101. }
  8102. if (ATOMIC_START_TOKEN[S.token.type]) {
  8103. return subscripts(as_atom_node(), allow_calls);
  8104. }
  8105. unexpected();
  8106. };
  8107. function expr_list(closing, allow_trailing_comma, allow_empty) {
  8108. var first = true, a = [];
  8109. while (!is("punc", closing)) {
  8110. if (first) first = false; else expect(",");
  8111. if (allow_trailing_comma && is("punc", closing)) break;
  8112. if (is("punc", ",") && allow_empty) {
  8113. a.push(new AST_Hole({ start: S.token, end: S.token }));
  8114. } else {
  8115. a.push(expression(false));
  8116. }
  8117. }
  8118. next();
  8119. return a;
  8120. };
  8121. var array_ = embed_tokens(function() {
  8122. expect("[");
  8123. return new AST_Array({
  8124. elements: expr_list("]", !options.strict, true)
  8125. });
  8126. });
  8127. var object_ = embed_tokens(function() {
  8128. expect("{");
  8129. var first = true, a = [];
  8130. while (!is("punc", "}")) {
  8131. if (first) first = false; else expect(",");
  8132. if (!options.strict && is("punc", "}"))
  8133. // allow trailing comma
  8134. break;
  8135. var start = S.token;
  8136. var type = start.type;
  8137. var name = as_property_name();
  8138. if (type == "name" && !is("punc", ":")) {
  8139. if (name == "get") {
  8140. a.push(new AST_ObjectGetter({
  8141. start : start,
  8142. key : as_atom_node(),
  8143. value : function_(AST_Accessor),
  8144. end : prev()
  8145. }));
  8146. continue;
  8147. }
  8148. if (name == "set") {
  8149. a.push(new AST_ObjectSetter({
  8150. start : start,
  8151. key : as_atom_node(),
  8152. value : function_(AST_Accessor),
  8153. end : prev()
  8154. }));
  8155. continue;
  8156. }
  8157. }
  8158. expect(":");
  8159. a.push(new AST_ObjectKeyVal({
  8160. start : start,
  8161. key : name,
  8162. value : expression(false),
  8163. end : prev()
  8164. }));
  8165. }
  8166. next();
  8167. return new AST_Object({ properties: a });
  8168. });
  8169. function as_property_name() {
  8170. var tmp = S.token;
  8171. next();
  8172. switch (tmp.type) {
  8173. case "num":
  8174. case "string":
  8175. case "name":
  8176. case "operator":
  8177. case "keyword":
  8178. case "atom":
  8179. return tmp.value;
  8180. default:
  8181. unexpected();
  8182. }
  8183. };
  8184. function as_name() {
  8185. var tmp = S.token;
  8186. next();
  8187. switch (tmp.type) {
  8188. case "name":
  8189. case "operator":
  8190. case "keyword":
  8191. case "atom":
  8192. return tmp.value;
  8193. default:
  8194. unexpected();
  8195. }
  8196. };
  8197. function _make_symbol(type) {
  8198. var name = S.token.value;
  8199. return new (name == "this" ? AST_This : type)({
  8200. name : String(name),
  8201. start : S.token,
  8202. end : S.token
  8203. });
  8204. };
  8205. function as_symbol(type, noerror) {
  8206. if (!is("name")) {
  8207. if (!noerror) croak("Name expected");
  8208. return null;
  8209. }
  8210. var sym = _make_symbol(type);
  8211. next();
  8212. return sym;
  8213. };
  8214. var subscripts = function(expr, allow_calls) {
  8215. var start = expr.start;
  8216. if (is("punc", ".")) {
  8217. next();
  8218. return subscripts(new AST_Dot({
  8219. start : start,
  8220. expression : expr,
  8221. property : as_name(),
  8222. end : prev()
  8223. }), allow_calls);
  8224. }
  8225. if (is("punc", "[")) {
  8226. next();
  8227. var prop = expression(true);
  8228. expect("]");
  8229. return subscripts(new AST_Sub({
  8230. start : start,
  8231. expression : expr,
  8232. property : prop,
  8233. end : prev()
  8234. }), allow_calls);
  8235. }
  8236. if (allow_calls && is("punc", "(")) {
  8237. next();
  8238. return subscripts(new AST_Call({
  8239. start : start,
  8240. expression : expr,
  8241. args : expr_list(")"),
  8242. end : prev()
  8243. }), true);
  8244. }
  8245. return expr;
  8246. };
  8247. var maybe_unary = function(allow_calls) {
  8248. var start = S.token;
  8249. if (is("operator") && UNARY_PREFIX(start.value)) {
  8250. next();
  8251. handle_regexp();
  8252. var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
  8253. ex.start = start;
  8254. ex.end = prev();
  8255. return ex;
  8256. }
  8257. var val = expr_atom(allow_calls);
  8258. while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
  8259. val = make_unary(AST_UnaryPostfix, S.token.value, val);
  8260. val.start = start;
  8261. val.end = S.token;
  8262. next();
  8263. }
  8264. return val;
  8265. };
  8266. function make_unary(ctor, op, expr) {
  8267. if ((op == "++" || op == "--") && !is_assignable(expr))
  8268. croak("Invalid use of " + op + " operator");
  8269. return new ctor({ operator: op, expression: expr });
  8270. };
  8271. var expr_op = function(left, min_prec, no_in) {
  8272. var op = is("operator") ? S.token.value : null;
  8273. if (op == "in" && no_in) op = null;
  8274. var prec = op != null ? PRECEDENCE[op] : null;
  8275. if (prec != null && prec > min_prec) {
  8276. next();
  8277. var right = expr_op(maybe_unary(true), prec, no_in);
  8278. return expr_op(new AST_Binary({
  8279. start : left.start,
  8280. left : left,
  8281. operator : op,
  8282. right : right,
  8283. end : right.end
  8284. }), min_prec, no_in);
  8285. }
  8286. return left;
  8287. };
  8288. function expr_ops(no_in) {
  8289. return expr_op(maybe_unary(true), 0, no_in);
  8290. };
  8291. var maybe_conditional = function(no_in) {
  8292. var start = S.token;
  8293. var expr = expr_ops(no_in);
  8294. if (is("operator", "?")) {
  8295. next();
  8296. var yes = expression(false);
  8297. expect(":");
  8298. return new AST_Conditional({
  8299. start : start,
  8300. condition : expr,
  8301. consequent : yes,
  8302. alternative : expression(false, no_in),
  8303. end : peek()
  8304. });
  8305. }
  8306. return expr;
  8307. };
  8308. function is_assignable(expr) {
  8309. if (!options.strict) return true;
  8310. if (expr instanceof AST_This) return false;
  8311. return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
  8312. };
  8313. var maybe_assign = function(no_in) {
  8314. var start = S.token;
  8315. var left = maybe_conditional(no_in), val = S.token.value;
  8316. if (is("operator") && ASSIGNMENT(val)) {
  8317. if (is_assignable(left)) {
  8318. next();
  8319. return new AST_Assign({
  8320. start : start,
  8321. left : left,
  8322. operator : val,
  8323. right : maybe_assign(no_in),
  8324. end : prev()
  8325. });
  8326. }
  8327. croak("Invalid assignment");
  8328. }
  8329. return left;
  8330. };
  8331. var expression = function(commas, no_in) {
  8332. var start = S.token;
  8333. var expr = maybe_assign(no_in);
  8334. if (commas && is("punc", ",")) {
  8335. next();
  8336. return new AST_Seq({
  8337. start : start,
  8338. car : expr,
  8339. cdr : expression(true, no_in),
  8340. end : peek()
  8341. });
  8342. }
  8343. return expr;
  8344. };
  8345. function in_loop(cont) {
  8346. ++S.in_loop;
  8347. var ret = cont();
  8348. --S.in_loop;
  8349. return ret;
  8350. };
  8351. if (options.expression) {
  8352. return expression(true);
  8353. }
  8354. return (function(){
  8355. var start = S.token;
  8356. var body = [];
  8357. while (!is("eof"))
  8358. body.push(statement());
  8359. var end = prev();
  8360. var toplevel = options.toplevel;
  8361. if (toplevel) {
  8362. toplevel.body = toplevel.body.concat(body);
  8363. toplevel.end = end;
  8364. } else {
  8365. toplevel = new AST_Toplevel({ start: start, body: body, end: end });
  8366. }
  8367. return toplevel;
  8368. })();
  8369. };
  8370. /***********************************************************************
  8371. A JavaScript tokenizer / parser / beautifier / compressor.
  8372. https://github.com/mishoo/UglifyJS2
  8373. -------------------------------- (C) ---------------------------------
  8374. Author: Mihai Bazon
  8375. <mihai.bazon@gmail.com>
  8376. http://mihai.bazon.net/blog
  8377. Distributed under the BSD license:
  8378. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  8379. Redistribution and use in source and binary forms, with or without
  8380. modification, are permitted provided that the following conditions
  8381. are met:
  8382. * Redistributions of source code must retain the above
  8383. copyright notice, this list of conditions and the following
  8384. disclaimer.
  8385. * Redistributions in binary form must reproduce the above
  8386. copyright notice, this list of conditions and the following
  8387. disclaimer in the documentation and/or other materials
  8388. provided with the distribution.
  8389. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  8390. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  8391. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  8392. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  8393. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  8394. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  8395. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  8396. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  8397. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  8398. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  8399. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  8400. SUCH DAMAGE.
  8401. ***********************************************************************/
  8402. "use strict";
  8403. // Tree transformer helpers.
  8404. function TreeTransformer(before, after) {
  8405. TreeWalker.call(this);
  8406. this.before = before;
  8407. this.after = after;
  8408. }
  8409. TreeTransformer.prototype = new TreeWalker;
  8410. (function(undefined){
  8411. function _(node, descend) {
  8412. node.DEFMETHOD("transform", function(tw, in_list){
  8413. var x, y;
  8414. tw.push(this);
  8415. if (tw.before) x = tw.before(this, descend, in_list);
  8416. if (x === undefined) {
  8417. if (!tw.after) {
  8418. x = this;
  8419. descend(x, tw);
  8420. } else {
  8421. tw.stack[tw.stack.length - 1] = x = this.clone();
  8422. descend(x, tw);
  8423. y = tw.after(x, in_list);
  8424. if (y !== undefined) x = y;
  8425. }
  8426. }
  8427. tw.pop();
  8428. return x;
  8429. });
  8430. };
  8431. function do_list(list, tw) {
  8432. return MAP(list, function(node){
  8433. return node.transform(tw, true);
  8434. });
  8435. };
  8436. _(AST_Node, noop);
  8437. _(AST_LabeledStatement, function(self, tw){
  8438. self.label = self.label.transform(tw);
  8439. self.body = self.body.transform(tw);
  8440. });
  8441. _(AST_SimpleStatement, function(self, tw){
  8442. self.body = self.body.transform(tw);
  8443. });
  8444. _(AST_Block, function(self, tw){
  8445. self.body = do_list(self.body, tw);
  8446. });
  8447. _(AST_DWLoop, function(self, tw){
  8448. self.condition = self.condition.transform(tw);
  8449. self.body = self.body.transform(tw);
  8450. });
  8451. _(AST_For, function(self, tw){
  8452. if (self.init) self.init = self.init.transform(tw);
  8453. if (self.condition) self.condition = self.condition.transform(tw);
  8454. if (self.step) self.step = self.step.transform(tw);
  8455. self.body = self.body.transform(tw);
  8456. });
  8457. _(AST_ForIn, function(self, tw){
  8458. self.init = self.init.transform(tw);
  8459. self.object = self.object.transform(tw);
  8460. self.body = self.body.transform(tw);
  8461. });
  8462. _(AST_With, function(self, tw){
  8463. self.expression = self.expression.transform(tw);
  8464. self.body = self.body.transform(tw);
  8465. });
  8466. _(AST_Exit, function(self, tw){
  8467. if (self.value) self.value = self.value.transform(tw);
  8468. });
  8469. _(AST_LoopControl, function(self, tw){
  8470. if (self.label) self.label = self.label.transform(tw);
  8471. });
  8472. _(AST_If, function(self, tw){
  8473. self.condition = self.condition.transform(tw);
  8474. self.body = self.body.transform(tw);
  8475. if (self.alternative) self.alternative = self.alternative.transform(tw);
  8476. });
  8477. _(AST_Switch, function(self, tw){
  8478. self.expression = self.expression.transform(tw);
  8479. self.body = do_list(self.body, tw);
  8480. });
  8481. _(AST_Case, function(self, tw){
  8482. self.expression = self.expression.transform(tw);
  8483. self.body = do_list(self.body, tw);
  8484. });
  8485. _(AST_Try, function(self, tw){
  8486. self.body = do_list(self.body, tw);
  8487. if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
  8488. if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
  8489. });
  8490. _(AST_Catch, function(self, tw){
  8491. self.argname = self.argname.transform(tw);
  8492. self.body = do_list(self.body, tw);
  8493. });
  8494. _(AST_Definitions, function(self, tw){
  8495. self.definitions = do_list(self.definitions, tw);
  8496. });
  8497. _(AST_VarDef, function(self, tw){
  8498. self.name = self.name.transform(tw);
  8499. if (self.value) self.value = self.value.transform(tw);
  8500. });
  8501. _(AST_Lambda, function(self, tw){
  8502. if (self.name) self.name = self.name.transform(tw);
  8503. self.argnames = do_list(self.argnames, tw);
  8504. self.body = do_list(self.body, tw);
  8505. });
  8506. _(AST_Call, function(self, tw){
  8507. self.expression = self.expression.transform(tw);
  8508. self.args = do_list(self.args, tw);
  8509. });
  8510. _(AST_Seq, function(self, tw){
  8511. self.car = self.car.transform(tw);
  8512. self.cdr = self.cdr.transform(tw);
  8513. });
  8514. _(AST_Dot, function(self, tw){
  8515. self.expression = self.expression.transform(tw);
  8516. });
  8517. _(AST_Sub, function(self, tw){
  8518. self.expression = self.expression.transform(tw);
  8519. self.property = self.property.transform(tw);
  8520. });
  8521. _(AST_Unary, function(self, tw){
  8522. self.expression = self.expression.transform(tw);
  8523. });
  8524. _(AST_Binary, function(self, tw){
  8525. self.left = self.left.transform(tw);
  8526. self.right = self.right.transform(tw);
  8527. });
  8528. _(AST_Conditional, function(self, tw){
  8529. self.condition = self.condition.transform(tw);
  8530. self.consequent = self.consequent.transform(tw);
  8531. self.alternative = self.alternative.transform(tw);
  8532. });
  8533. _(AST_Array, function(self, tw){
  8534. self.elements = do_list(self.elements, tw);
  8535. });
  8536. _(AST_Object, function(self, tw){
  8537. self.properties = do_list(self.properties, tw);
  8538. });
  8539. _(AST_ObjectProperty, function(self, tw){
  8540. self.value = self.value.transform(tw);
  8541. });
  8542. })();
  8543. /***********************************************************************
  8544. A JavaScript tokenizer / parser / beautifier / compressor.
  8545. https://github.com/mishoo/UglifyJS2
  8546. -------------------------------- (C) ---------------------------------
  8547. Author: Mihai Bazon
  8548. <mihai.bazon@gmail.com>
  8549. http://mihai.bazon.net/blog
  8550. Distributed under the BSD license:
  8551. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  8552. Redistribution and use in source and binary forms, with or without
  8553. modification, are permitted provided that the following conditions
  8554. are met:
  8555. * Redistributions of source code must retain the above
  8556. copyright notice, this list of conditions and the following
  8557. disclaimer.
  8558. * Redistributions in binary form must reproduce the above
  8559. copyright notice, this list of conditions and the following
  8560. disclaimer in the documentation and/or other materials
  8561. provided with the distribution.
  8562. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  8563. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  8564. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  8565. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  8566. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  8567. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  8568. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  8569. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  8570. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  8571. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  8572. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  8573. SUCH DAMAGE.
  8574. ***********************************************************************/
  8575. "use strict";
  8576. function SymbolDef(scope, index, orig) {
  8577. this.name = orig.name;
  8578. this.orig = [ orig ];
  8579. this.scope = scope;
  8580. this.references = [];
  8581. this.global = false;
  8582. this.mangled_name = null;
  8583. this.undeclared = false;
  8584. this.constant = false;
  8585. this.index = index;
  8586. };
  8587. SymbolDef.prototype = {
  8588. unmangleable: function(options) {
  8589. return (this.global && !(options && options.toplevel))
  8590. || this.undeclared
  8591. || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with));
  8592. },
  8593. mangle: function(options) {
  8594. if (!this.mangled_name && !this.unmangleable(options)) {
  8595. var s = this.scope;
  8596. if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
  8597. s = s.parent_scope;
  8598. this.mangled_name = s.next_mangled(options, this);
  8599. }
  8600. }
  8601. };
  8602. AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
  8603. options = defaults(options, {
  8604. screw_ie8: false
  8605. });
  8606. // pass 1: setup scope chaining and handle definitions
  8607. var self = this;
  8608. var scope = self.parent_scope = null;
  8609. var defun = null;
  8610. var nesting = 0;
  8611. var tw = new TreeWalker(function(node, descend){
  8612. if (options.screw_ie8 && node instanceof AST_Catch) {
  8613. var save_scope = scope;
  8614. scope = new AST_Scope(node);
  8615. scope.init_scope_vars(nesting);
  8616. scope.parent_scope = save_scope;
  8617. descend();
  8618. scope = save_scope;
  8619. return true;
  8620. }
  8621. if (node instanceof AST_Scope) {
  8622. node.init_scope_vars(nesting);
  8623. var save_scope = node.parent_scope = scope;
  8624. var save_defun = defun;
  8625. defun = scope = node;
  8626. ++nesting; descend(); --nesting;
  8627. scope = save_scope;
  8628. defun = save_defun;
  8629. return true; // don't descend again in TreeWalker
  8630. }
  8631. if (node instanceof AST_Directive) {
  8632. node.scope = scope;
  8633. push_uniq(scope.directives, node.value);
  8634. return true;
  8635. }
  8636. if (node instanceof AST_With) {
  8637. for (var s = scope; s; s = s.parent_scope)
  8638. s.uses_with = true;
  8639. return;
  8640. }
  8641. if (node instanceof AST_Symbol) {
  8642. node.scope = scope;
  8643. }
  8644. if (node instanceof AST_SymbolLambda) {
  8645. defun.def_function(node);
  8646. }
  8647. else if (node instanceof AST_SymbolDefun) {
  8648. // Careful here, the scope where this should be defined is
  8649. // the parent scope. The reason is that we enter a new
  8650. // scope when we encounter the AST_Defun node (which is
  8651. // instanceof AST_Scope) but we get to the symbol a bit
  8652. // later.
  8653. (node.scope = defun.parent_scope).def_function(node);
  8654. }
  8655. else if (node instanceof AST_SymbolVar
  8656. || node instanceof AST_SymbolConst) {
  8657. var def = defun.def_variable(node);
  8658. def.constant = node instanceof AST_SymbolConst;
  8659. def.init = tw.parent().value;
  8660. }
  8661. else if (node instanceof AST_SymbolCatch) {
  8662. (options.screw_ie8 ? scope : defun)
  8663. .def_variable(node);
  8664. }
  8665. });
  8666. self.walk(tw);
  8667. // pass 2: find back references and eval
  8668. var func = null;
  8669. var globals = self.globals = new Dictionary();
  8670. var tw = new TreeWalker(function(node, descend){
  8671. if (node instanceof AST_Lambda) {
  8672. var prev_func = func;
  8673. func = node;
  8674. descend();
  8675. func = prev_func;
  8676. return true;
  8677. }
  8678. if (node instanceof AST_SymbolRef) {
  8679. var name = node.name;
  8680. var sym = node.scope.find_variable(name);
  8681. if (!sym) {
  8682. var g;
  8683. if (globals.has(name)) {
  8684. g = globals.get(name);
  8685. } else {
  8686. g = new SymbolDef(self, globals.size(), node);
  8687. g.undeclared = true;
  8688. g.global = true;
  8689. globals.set(name, g);
  8690. }
  8691. node.thedef = g;
  8692. if (name == "eval" && tw.parent() instanceof AST_Call) {
  8693. for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
  8694. s.uses_eval = true;
  8695. }
  8696. if (func && name == "arguments") {
  8697. func.uses_arguments = true;
  8698. }
  8699. } else {
  8700. node.thedef = sym;
  8701. }
  8702. node.reference();
  8703. return true;
  8704. }
  8705. });
  8706. self.walk(tw);
  8707. });
  8708. AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
  8709. this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
  8710. this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
  8711. this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
  8712. this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
  8713. this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
  8714. this.parent_scope = null; // the parent scope
  8715. this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
  8716. this.cname = -1; // the current index for mangling functions/variables
  8717. this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
  8718. });
  8719. AST_Scope.DEFMETHOD("strict", function(){
  8720. return this.has_directive("use strict");
  8721. });
  8722. AST_Lambda.DEFMETHOD("init_scope_vars", function(){
  8723. AST_Scope.prototype.init_scope_vars.apply(this, arguments);
  8724. this.uses_arguments = false;
  8725. });
  8726. AST_SymbolRef.DEFMETHOD("reference", function() {
  8727. var def = this.definition();
  8728. def.references.push(this);
  8729. var s = this.scope;
  8730. while (s) {
  8731. push_uniq(s.enclosed, def);
  8732. if (s === def.scope) break;
  8733. s = s.parent_scope;
  8734. }
  8735. this.frame = this.scope.nesting - def.scope.nesting;
  8736. });
  8737. AST_Scope.DEFMETHOD("find_variable", function(name){
  8738. if (name instanceof AST_Symbol) name = name.name;
  8739. return this.variables.get(name)
  8740. || (this.parent_scope && this.parent_scope.find_variable(name));
  8741. });
  8742. AST_Scope.DEFMETHOD("has_directive", function(value){
  8743. return this.parent_scope && this.parent_scope.has_directive(value)
  8744. || (this.directives.indexOf(value) >= 0 ? this : null);
  8745. });
  8746. AST_Scope.DEFMETHOD("def_function", function(symbol){
  8747. this.functions.set(symbol.name, this.def_variable(symbol));
  8748. });
  8749. AST_Scope.DEFMETHOD("def_variable", function(symbol){
  8750. var def;
  8751. if (!this.variables.has(symbol.name)) {
  8752. def = new SymbolDef(this, this.variables.size(), symbol);
  8753. this.variables.set(symbol.name, def);
  8754. def.global = !this.parent_scope;
  8755. } else {
  8756. def = this.variables.get(symbol.name);
  8757. def.orig.push(symbol);
  8758. }
  8759. return symbol.thedef = def;
  8760. });
  8761. AST_Scope.DEFMETHOD("next_mangled", function(options){
  8762. var ext = this.enclosed;
  8763. out: while (true) {
  8764. var m = base54(++this.cname);
  8765. if (!is_identifier(m)) continue; // skip over "do"
  8766. // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
  8767. // shadow a name excepted from mangling.
  8768. if (options.except.indexOf(m) >= 0) continue;
  8769. // we must ensure that the mangled name does not shadow a name
  8770. // from some parent scope that is referenced in this or in
  8771. // inner scopes.
  8772. for (var i = ext.length; --i >= 0;) {
  8773. var sym = ext[i];
  8774. var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
  8775. if (m == name) continue out;
  8776. }
  8777. return m;
  8778. }
  8779. });
  8780. AST_Function.DEFMETHOD("next_mangled", function(options, def){
  8781. // #179, #326
  8782. // in Safari strict mode, something like (function x(x){...}) is a syntax error;
  8783. // a function expression's argument cannot shadow the function expression's name
  8784. var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
  8785. while (true) {
  8786. var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
  8787. if (!(tricky_def && tricky_def.mangled_name == name))
  8788. return name;
  8789. }
  8790. });
  8791. AST_Scope.DEFMETHOD("references", function(sym){
  8792. if (sym instanceof AST_Symbol) sym = sym.definition();
  8793. return this.enclosed.indexOf(sym) < 0 ? null : sym;
  8794. });
  8795. AST_Symbol.DEFMETHOD("unmangleable", function(options){
  8796. return this.definition().unmangleable(options);
  8797. });
  8798. // property accessors are not mangleable
  8799. AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
  8800. return true;
  8801. });
  8802. // labels are always mangleable
  8803. AST_Label.DEFMETHOD("unmangleable", function(){
  8804. return false;
  8805. });
  8806. AST_Symbol.DEFMETHOD("unreferenced", function(){
  8807. return this.definition().references.length == 0
  8808. && !(this.scope.uses_eval || this.scope.uses_with);
  8809. });
  8810. AST_Symbol.DEFMETHOD("undeclared", function(){
  8811. return this.definition().undeclared;
  8812. });
  8813. AST_LabelRef.DEFMETHOD("undeclared", function(){
  8814. return false;
  8815. });
  8816. AST_Label.DEFMETHOD("undeclared", function(){
  8817. return false;
  8818. });
  8819. AST_Symbol.DEFMETHOD("definition", function(){
  8820. return this.thedef;
  8821. });
  8822. AST_Symbol.DEFMETHOD("global", function(){
  8823. return this.definition().global;
  8824. });
  8825. AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
  8826. return defaults(options, {
  8827. except : [],
  8828. eval : false,
  8829. sort : false,
  8830. toplevel : false,
  8831. screw_ie8 : false
  8832. });
  8833. });
  8834. AST_Toplevel.DEFMETHOD("mangle_names", function(options){
  8835. options = this._default_mangler_options(options);
  8836. // We only need to mangle declaration nodes. Special logic wired
  8837. // into the code generator will display the mangled name if it's
  8838. // present (and for AST_SymbolRef-s it'll use the mangled name of
  8839. // the AST_SymbolDeclaration that it points to).
  8840. var lname = -1;
  8841. var to_mangle = [];
  8842. var tw = new TreeWalker(function(node, descend){
  8843. if (node instanceof AST_LabeledStatement) {
  8844. // lname is incremented when we get to the AST_Label
  8845. var save_nesting = lname;
  8846. descend();
  8847. lname = save_nesting;
  8848. return true; // don't descend again in TreeWalker
  8849. }
  8850. if (node instanceof AST_Scope) {
  8851. var p = tw.parent(), a = [];
  8852. node.variables.each(function(symbol){
  8853. if (options.except.indexOf(symbol.name) < 0) {
  8854. a.push(symbol);
  8855. }
  8856. });
  8857. if (options.sort) a.sort(function(a, b){
  8858. return b.references.length - a.references.length;
  8859. });
  8860. to_mangle.push.apply(to_mangle, a);
  8861. return;
  8862. }
  8863. if (node instanceof AST_Label) {
  8864. var name;
  8865. do name = base54(++lname); while (!is_identifier(name));
  8866. node.mangled_name = name;
  8867. return true;
  8868. }
  8869. });
  8870. this.walk(tw);
  8871. to_mangle.forEach(function(def){ def.mangle(options) });
  8872. });
  8873. AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
  8874. options = this._default_mangler_options(options);
  8875. var tw = new TreeWalker(function(node){
  8876. if (node instanceof AST_Constant)
  8877. base54.consider(node.print_to_string());
  8878. else if (node instanceof AST_Return)
  8879. base54.consider("return");
  8880. else if (node instanceof AST_Throw)
  8881. base54.consider("throw");
  8882. else if (node instanceof AST_Continue)
  8883. base54.consider("continue");
  8884. else if (node instanceof AST_Break)
  8885. base54.consider("break");
  8886. else if (node instanceof AST_Debugger)
  8887. base54.consider("debugger");
  8888. else if (node instanceof AST_Directive)
  8889. base54.consider(node.value);
  8890. else if (node instanceof AST_While)
  8891. base54.consider("while");
  8892. else if (node instanceof AST_Do)
  8893. base54.consider("do while");
  8894. else if (node instanceof AST_If) {
  8895. base54.consider("if");
  8896. if (node.alternative) base54.consider("else");
  8897. }
  8898. else if (node instanceof AST_Var)
  8899. base54.consider("var");
  8900. else if (node instanceof AST_Const)
  8901. base54.consider("const");
  8902. else if (node instanceof AST_Lambda)
  8903. base54.consider("function");
  8904. else if (node instanceof AST_For)
  8905. base54.consider("for");
  8906. else if (node instanceof AST_ForIn)
  8907. base54.consider("for in");
  8908. else if (node instanceof AST_Switch)
  8909. base54.consider("switch");
  8910. else if (node instanceof AST_Case)
  8911. base54.consider("case");
  8912. else if (node instanceof AST_Default)
  8913. base54.consider("default");
  8914. else if (node instanceof AST_With)
  8915. base54.consider("with");
  8916. else if (node instanceof AST_ObjectSetter)
  8917. base54.consider("set" + node.key);
  8918. else if (node instanceof AST_ObjectGetter)
  8919. base54.consider("get" + node.key);
  8920. else if (node instanceof AST_ObjectKeyVal)
  8921. base54.consider(node.key);
  8922. else if (node instanceof AST_New)
  8923. base54.consider("new");
  8924. else if (node instanceof AST_This)
  8925. base54.consider("this");
  8926. else if (node instanceof AST_Try)
  8927. base54.consider("try");
  8928. else if (node instanceof AST_Catch)
  8929. base54.consider("catch");
  8930. else if (node instanceof AST_Finally)
  8931. base54.consider("finally");
  8932. else if (node instanceof AST_Symbol && node.unmangleable(options))
  8933. base54.consider(node.name);
  8934. else if (node instanceof AST_Unary || node instanceof AST_Binary)
  8935. base54.consider(node.operator);
  8936. else if (node instanceof AST_Dot)
  8937. base54.consider(node.property);
  8938. });
  8939. this.walk(tw);
  8940. base54.sort();
  8941. });
  8942. var base54 = (function() {
  8943. var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
  8944. var chars, frequency;
  8945. function reset() {
  8946. frequency = Object.create(null);
  8947. chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
  8948. chars.forEach(function(ch){ frequency[ch] = 0 });
  8949. }
  8950. base54.consider = function(str){
  8951. for (var i = str.length; --i >= 0;) {
  8952. var code = str.charCodeAt(i);
  8953. if (code in frequency) ++frequency[code];
  8954. }
  8955. };
  8956. base54.sort = function() {
  8957. chars = mergeSort(chars, function(a, b){
  8958. if (is_digit(a) && !is_digit(b)) return 1;
  8959. if (is_digit(b) && !is_digit(a)) return -1;
  8960. return frequency[b] - frequency[a];
  8961. });
  8962. };
  8963. base54.reset = reset;
  8964. reset();
  8965. base54.get = function(){ return chars };
  8966. base54.freq = function(){ return frequency };
  8967. function base54(num) {
  8968. var ret = "", base = 54;
  8969. do {
  8970. ret += String.fromCharCode(chars[num % base]);
  8971. num = Math.floor(num / base);
  8972. base = 64;
  8973. } while (num > 0);
  8974. return ret;
  8975. };
  8976. return base54;
  8977. })();
  8978. AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
  8979. options = defaults(options, {
  8980. undeclared : false, // this makes a lot of noise
  8981. unreferenced : true,
  8982. assign_to_global : true,
  8983. func_arguments : true,
  8984. nested_defuns : true,
  8985. eval : true
  8986. });
  8987. var tw = new TreeWalker(function(node){
  8988. if (options.undeclared
  8989. && node instanceof AST_SymbolRef
  8990. && node.undeclared())
  8991. {
  8992. // XXX: this also warns about JS standard names,
  8993. // i.e. Object, Array, parseInt etc. Should add a list of
  8994. // exceptions.
  8995. AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
  8996. name: node.name,
  8997. file: node.start.file,
  8998. line: node.start.line,
  8999. col: node.start.col
  9000. });
  9001. }
  9002. if (options.assign_to_global)
  9003. {
  9004. var sym = null;
  9005. if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
  9006. sym = node.left;
  9007. else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
  9008. sym = node.init;
  9009. if (sym
  9010. && (sym.undeclared()
  9011. || (sym.global() && sym.scope !== sym.definition().scope))) {
  9012. AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
  9013. msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
  9014. name: sym.name,
  9015. file: sym.start.file,
  9016. line: sym.start.line,
  9017. col: sym.start.col
  9018. });
  9019. }
  9020. }
  9021. if (options.eval
  9022. && node instanceof AST_SymbolRef
  9023. && node.undeclared()
  9024. && node.name == "eval") {
  9025. AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
  9026. }
  9027. if (options.unreferenced
  9028. && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
  9029. && node.unreferenced()) {
  9030. AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
  9031. type: node instanceof AST_Label ? "Label" : "Symbol",
  9032. name: node.name,
  9033. file: node.start.file,
  9034. line: node.start.line,
  9035. col: node.start.col
  9036. });
  9037. }
  9038. if (options.func_arguments
  9039. && node instanceof AST_Lambda
  9040. && node.uses_arguments) {
  9041. AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
  9042. name: node.name ? node.name.name : "anonymous",
  9043. file: node.start.file,
  9044. line: node.start.line,
  9045. col: node.start.col
  9046. });
  9047. }
  9048. if (options.nested_defuns
  9049. && node instanceof AST_Defun
  9050. && !(tw.parent() instanceof AST_Scope)) {
  9051. AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
  9052. name: node.name.name,
  9053. type: tw.parent().TYPE,
  9054. file: node.start.file,
  9055. line: node.start.line,
  9056. col: node.start.col
  9057. });
  9058. }
  9059. });
  9060. this.walk(tw);
  9061. });
  9062. /***********************************************************************
  9063. A JavaScript tokenizer / parser / beautifier / compressor.
  9064. https://github.com/mishoo/UglifyJS2
  9065. -------------------------------- (C) ---------------------------------
  9066. Author: Mihai Bazon
  9067. <mihai.bazon@gmail.com>
  9068. http://mihai.bazon.net/blog
  9069. Distributed under the BSD license:
  9070. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  9071. Redistribution and use in source and binary forms, with or without
  9072. modification, are permitted provided that the following conditions
  9073. are met:
  9074. * Redistributions of source code must retain the above
  9075. copyright notice, this list of conditions and the following
  9076. disclaimer.
  9077. * Redistributions in binary form must reproduce the above
  9078. copyright notice, this list of conditions and the following
  9079. disclaimer in the documentation and/or other materials
  9080. provided with the distribution.
  9081. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  9082. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  9083. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  9084. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  9085. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  9086. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  9087. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  9088. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  9089. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  9090. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  9091. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  9092. SUCH DAMAGE.
  9093. ***********************************************************************/
  9094. "use strict";
  9095. function OutputStream(options) {
  9096. options = defaults(options, {
  9097. indent_start : 0,
  9098. indent_level : 4,
  9099. quote_keys : false,
  9100. space_colon : true,
  9101. ascii_only : false,
  9102. inline_script : false,
  9103. width : 80,
  9104. max_line_len : 32000,
  9105. beautify : false,
  9106. source_map : null,
  9107. bracketize : false,
  9108. semicolons : true,
  9109. comments : false,
  9110. preserve_line : false,
  9111. screw_ie8 : false,
  9112. preamble : null,
  9113. }, true);
  9114. var indentation = 0;
  9115. var current_col = 0;
  9116. var current_line = 1;
  9117. var current_pos = 0;
  9118. var OUTPUT = "";
  9119. function to_ascii(str, identifier) {
  9120. return str.replace(/[\u0080-\uffff]/g, function(ch) {
  9121. var code = ch.charCodeAt(0).toString(16);
  9122. if (code.length <= 2 && !identifier) {
  9123. while (code.length < 2) code = "0" + code;
  9124. return "\\x" + code;
  9125. } else {
  9126. while (code.length < 4) code = "0" + code;
  9127. return "\\u" + code;
  9128. }
  9129. });
  9130. };
  9131. function make_string(str) {
  9132. var dq = 0, sq = 0;
  9133. str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
  9134. switch (s) {
  9135. case "\\": return "\\\\";
  9136. case "\b": return "\\b";
  9137. case "\f": return "\\f";
  9138. case "\n": return "\\n";
  9139. case "\r": return "\\r";
  9140. case "\u2028": return "\\u2028";
  9141. case "\u2029": return "\\u2029";
  9142. case '"': ++dq; return '"';
  9143. case "'": ++sq; return "'";
  9144. case "\0": return "\\x00";
  9145. }
  9146. return s;
  9147. });
  9148. if (options.ascii_only) str = to_ascii(str);
  9149. if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
  9150. else return '"' + str.replace(/\x22/g, '\\"') + '"';
  9151. };
  9152. function encode_string(str) {
  9153. var ret = make_string(str);
  9154. if (options.inline_script)
  9155. ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
  9156. return ret;
  9157. };
  9158. function make_name(name) {
  9159. name = name.toString();
  9160. if (options.ascii_only)
  9161. name = to_ascii(name, true);
  9162. return name;
  9163. };
  9164. function make_indent(back) {
  9165. return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
  9166. };
  9167. /* -----[ beautification/minification ]----- */
  9168. var might_need_space = false;
  9169. var might_need_semicolon = false;
  9170. var last = null;
  9171. function last_char() {
  9172. return last.charAt(last.length - 1);
  9173. };
  9174. function maybe_newline() {
  9175. if (options.max_line_len && current_col > options.max_line_len)
  9176. print("\n");
  9177. };
  9178. var requireSemicolonChars = makePredicate("( [ + * / - , .");
  9179. function print(str) {
  9180. str = String(str);
  9181. var ch = str.charAt(0);
  9182. if (might_need_semicolon) {
  9183. if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
  9184. if (options.semicolons || requireSemicolonChars(ch)) {
  9185. OUTPUT += ";";
  9186. current_col++;
  9187. current_pos++;
  9188. } else {
  9189. OUTPUT += "\n";
  9190. current_pos++;
  9191. current_line++;
  9192. current_col = 0;
  9193. }
  9194. if (!options.beautify)
  9195. might_need_space = false;
  9196. }
  9197. might_need_semicolon = false;
  9198. maybe_newline();
  9199. }
  9200. if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
  9201. var target_line = stack[stack.length - 1].start.line;
  9202. while (current_line < target_line) {
  9203. OUTPUT += "\n";
  9204. current_pos++;
  9205. current_line++;
  9206. current_col = 0;
  9207. might_need_space = false;
  9208. }
  9209. }
  9210. if (might_need_space) {
  9211. var prev = last_char();
  9212. if ((is_identifier_char(prev)
  9213. && (is_identifier_char(ch) || ch == "\\"))
  9214. || (/^[\+\-\/]$/.test(ch) && ch == prev))
  9215. {
  9216. OUTPUT += " ";
  9217. current_col++;
  9218. current_pos++;
  9219. }
  9220. might_need_space = false;
  9221. }
  9222. var a = str.split(/\r?\n/), n = a.length - 1;
  9223. current_line += n;
  9224. if (n == 0) {
  9225. current_col += a[n].length;
  9226. } else {
  9227. current_col = a[n].length;
  9228. }
  9229. current_pos += str.length;
  9230. last = str;
  9231. OUTPUT += str;
  9232. };
  9233. var space = options.beautify ? function() {
  9234. print(" ");
  9235. } : function() {
  9236. might_need_space = true;
  9237. };
  9238. var indent = options.beautify ? function(half) {
  9239. if (options.beautify) {
  9240. print(make_indent(half ? 0.5 : 0));
  9241. }
  9242. } : noop;
  9243. var with_indent = options.beautify ? function(col, cont) {
  9244. if (col === true) col = next_indent();
  9245. var save_indentation = indentation;
  9246. indentation = col;
  9247. var ret = cont();
  9248. indentation = save_indentation;
  9249. return ret;
  9250. } : function(col, cont) { return cont() };
  9251. var newline = options.beautify ? function() {
  9252. print("\n");
  9253. } : noop;
  9254. var semicolon = options.beautify ? function() {
  9255. print(";");
  9256. } : function() {
  9257. might_need_semicolon = true;
  9258. };
  9259. function force_semicolon() {
  9260. might_need_semicolon = false;
  9261. print(";");
  9262. };
  9263. function next_indent() {
  9264. return indentation + options.indent_level;
  9265. };
  9266. function with_block(cont) {
  9267. var ret;
  9268. print("{");
  9269. newline();
  9270. with_indent(next_indent(), function(){
  9271. ret = cont();
  9272. });
  9273. indent();
  9274. print("}");
  9275. return ret;
  9276. };
  9277. function with_parens(cont) {
  9278. print("(");
  9279. //XXX: still nice to have that for argument lists
  9280. //var ret = with_indent(current_col, cont);
  9281. var ret = cont();
  9282. print(")");
  9283. return ret;
  9284. };
  9285. function with_square(cont) {
  9286. print("[");
  9287. //var ret = with_indent(current_col, cont);
  9288. var ret = cont();
  9289. print("]");
  9290. return ret;
  9291. };
  9292. function comma() {
  9293. print(",");
  9294. space();
  9295. };
  9296. function colon() {
  9297. print(":");
  9298. if (options.space_colon) space();
  9299. };
  9300. var add_mapping = options.source_map ? function(token, name) {
  9301. try {
  9302. if (token) options.source_map.add(
  9303. token.file || "?",
  9304. current_line, current_col,
  9305. token.line, token.col,
  9306. (!name && token.type == "name") ? token.value : name
  9307. );
  9308. } catch(ex) {
  9309. AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
  9310. file: token.file,
  9311. line: token.line,
  9312. col: token.col,
  9313. cline: current_line,
  9314. ccol: current_col,
  9315. name: name || ""
  9316. })
  9317. }
  9318. } : noop;
  9319. function get() {
  9320. return OUTPUT;
  9321. };
  9322. if (options.preamble) {
  9323. print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
  9324. }
  9325. var stack = [];
  9326. return {
  9327. get : get,
  9328. toString : get,
  9329. indent : indent,
  9330. indentation : function() { return indentation },
  9331. current_width : function() { return current_col - indentation },
  9332. should_break : function() { return options.width && this.current_width() >= options.width },
  9333. newline : newline,
  9334. print : print,
  9335. space : space,
  9336. comma : comma,
  9337. colon : colon,
  9338. last : function() { return last },
  9339. semicolon : semicolon,
  9340. force_semicolon : force_semicolon,
  9341. to_ascii : to_ascii,
  9342. print_name : function(name) { print(make_name(name)) },
  9343. print_string : function(str) { print(encode_string(str)) },
  9344. next_indent : next_indent,
  9345. with_indent : with_indent,
  9346. with_block : with_block,
  9347. with_parens : with_parens,
  9348. with_square : with_square,
  9349. add_mapping : add_mapping,
  9350. option : function(opt) { return options[opt] },
  9351. line : function() { return current_line },
  9352. col : function() { return current_col },
  9353. pos : function() { return current_pos },
  9354. push_node : function(node) { stack.push(node) },
  9355. pop_node : function() { return stack.pop() },
  9356. stack : function() { return stack },
  9357. parent : function(n) {
  9358. return stack[stack.length - 2 - (n || 0)];
  9359. }
  9360. };
  9361. };
  9362. /* -----[ code generators ]----- */
  9363. (function(){
  9364. /* -----[ utils ]----- */
  9365. function DEFPRINT(nodetype, generator) {
  9366. nodetype.DEFMETHOD("_codegen", generator);
  9367. };
  9368. AST_Node.DEFMETHOD("print", function(stream, force_parens){
  9369. var self = this, generator = self._codegen;
  9370. function doit() {
  9371. self.add_comments(stream);
  9372. self.add_source_map(stream);
  9373. generator(self, stream);
  9374. }
  9375. stream.push_node(self);
  9376. if (force_parens || self.needs_parens(stream)) {
  9377. stream.with_parens(doit);
  9378. } else {
  9379. doit();
  9380. }
  9381. stream.pop_node();
  9382. });
  9383. AST_Node.DEFMETHOD("print_to_string", function(options){
  9384. var s = OutputStream(options);
  9385. this.print(s);
  9386. return s.get();
  9387. });
  9388. /* -----[ comments ]----- */
  9389. AST_Node.DEFMETHOD("add_comments", function(output){
  9390. var c = output.option("comments"), self = this;
  9391. if (c) {
  9392. var start = self.start;
  9393. if (start && !start._comments_dumped) {
  9394. start._comments_dumped = true;
  9395. var comments = start.comments_before || [];
  9396. // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
  9397. // if this node is `return` or `throw`, we cannot allow comments before
  9398. // the returned or thrown value.
  9399. if (self instanceof AST_Exit && self.value
  9400. && self.value.start.comments_before
  9401. && self.value.start.comments_before.length > 0) {
  9402. comments = comments.concat(self.value.start.comments_before);
  9403. self.value.start.comments_before = [];
  9404. }
  9405. if (c.test) {
  9406. comments = comments.filter(function(comment){
  9407. return c.test(comment.value);
  9408. });
  9409. } else if (typeof c == "function") {
  9410. comments = comments.filter(function(comment){
  9411. return c(self, comment);
  9412. });
  9413. }
  9414. comments.forEach(function(c){
  9415. if (/comment[134]/.test(c.type)) {
  9416. output.print("//" + c.value + "\n");
  9417. output.indent();
  9418. }
  9419. else if (c.type == "comment2") {
  9420. output.print("/*" + c.value + "*/");
  9421. if (start.nlb) {
  9422. output.print("\n");
  9423. output.indent();
  9424. } else {
  9425. output.space();
  9426. }
  9427. }
  9428. });
  9429. }
  9430. }
  9431. });
  9432. /* -----[ PARENTHESES ]----- */
  9433. function PARENS(nodetype, func) {
  9434. nodetype.DEFMETHOD("needs_parens", func);
  9435. };
  9436. PARENS(AST_Node, function(){
  9437. return false;
  9438. });
  9439. // a function expression needs parens around it when it's provably
  9440. // the first token to appear in a statement.
  9441. PARENS(AST_Function, function(output){
  9442. return first_in_statement(output);
  9443. });
  9444. // same goes for an object literal, because otherwise it would be
  9445. // interpreted as a block of code.
  9446. PARENS(AST_Object, function(output){
  9447. return first_in_statement(output);
  9448. });
  9449. PARENS(AST_Unary, function(output){
  9450. var p = output.parent();
  9451. return p instanceof AST_PropAccess && p.expression === this;
  9452. });
  9453. PARENS(AST_Seq, function(output){
  9454. var p = output.parent();
  9455. return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
  9456. || p instanceof AST_Unary // !(foo, bar, baz)
  9457. || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
  9458. || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
  9459. || p instanceof AST_Dot // (1, {foo:2}).foo ==> 2
  9460. || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
  9461. || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
  9462. || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
  9463. * ==> 20 (side effect, set a := 10 and b := 20) */
  9464. ;
  9465. });
  9466. PARENS(AST_Binary, function(output){
  9467. var p = output.parent();
  9468. // (foo && bar)()
  9469. if (p instanceof AST_Call && p.expression === this)
  9470. return true;
  9471. // typeof (foo && bar)
  9472. if (p instanceof AST_Unary)
  9473. return true;
  9474. // (foo && bar)["prop"], (foo && bar).prop
  9475. if (p instanceof AST_PropAccess && p.expression === this)
  9476. return true;
  9477. // this deals with precedence: 3 * (2 + 1)
  9478. if (p instanceof AST_Binary) {
  9479. var po = p.operator, pp = PRECEDENCE[po];
  9480. var so = this.operator, sp = PRECEDENCE[so];
  9481. if (pp > sp
  9482. || (pp == sp
  9483. && this === p.right)) {
  9484. return true;
  9485. }
  9486. }
  9487. });
  9488. PARENS(AST_PropAccess, function(output){
  9489. var p = output.parent();
  9490. if (p instanceof AST_New && p.expression === this) {
  9491. // i.e. new (foo.bar().baz)
  9492. //
  9493. // if there's one call into this subtree, then we need
  9494. // parens around it too, otherwise the call will be
  9495. // interpreted as passing the arguments to the upper New
  9496. // expression.
  9497. try {
  9498. this.walk(new TreeWalker(function(node){
  9499. if (node instanceof AST_Call) throw p;
  9500. }));
  9501. } catch(ex) {
  9502. if (ex !== p) throw ex;
  9503. return true;
  9504. }
  9505. }
  9506. });
  9507. PARENS(AST_Call, function(output){
  9508. var p = output.parent(), p1;
  9509. if (p instanceof AST_New && p.expression === this)
  9510. return true;
  9511. // workaround for Safari bug.
  9512. // https://bugs.webkit.org/show_bug.cgi?id=123506
  9513. return this.expression instanceof AST_Function
  9514. && p instanceof AST_PropAccess
  9515. && p.expression === this
  9516. && (p1 = output.parent(1)) instanceof AST_Assign
  9517. && p1.left === p;
  9518. });
  9519. PARENS(AST_New, function(output){
  9520. var p = output.parent();
  9521. if (no_constructor_parens(this, output)
  9522. && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
  9523. || p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
  9524. return true;
  9525. });
  9526. PARENS(AST_Number, function(output){
  9527. var p = output.parent();
  9528. if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
  9529. return true;
  9530. });
  9531. PARENS(AST_NaN, function(output){
  9532. var p = output.parent();
  9533. if (p instanceof AST_PropAccess && p.expression === this)
  9534. return true;
  9535. });
  9536. function assign_and_conditional_paren_rules(output) {
  9537. var p = output.parent();
  9538. // !(a = false) → true
  9539. if (p instanceof AST_Unary)
  9540. return true;
  9541. // 1 + (a = 2) + 3 → 6, side effect setting a = 2
  9542. if (p instanceof AST_Binary && !(p instanceof AST_Assign))
  9543. return true;
  9544. // (a = func)() —or— new (a = Object)()
  9545. if (p instanceof AST_Call && p.expression === this)
  9546. return true;
  9547. // (a = foo) ? bar : baz
  9548. if (p instanceof AST_Conditional && p.condition === this)
  9549. return true;
  9550. // (a = foo)["prop"] —or— (a = foo).prop
  9551. if (p instanceof AST_PropAccess && p.expression === this)
  9552. return true;
  9553. };
  9554. PARENS(AST_Assign, assign_and_conditional_paren_rules);
  9555. PARENS(AST_Conditional, assign_and_conditional_paren_rules);
  9556. /* -----[ PRINTERS ]----- */
  9557. DEFPRINT(AST_Directive, function(self, output){
  9558. output.print_string(self.value);
  9559. output.semicolon();
  9560. });
  9561. DEFPRINT(AST_Debugger, function(self, output){
  9562. output.print("debugger");
  9563. output.semicolon();
  9564. });
  9565. /* -----[ statements ]----- */
  9566. function display_body(body, is_toplevel, output) {
  9567. var last = body.length - 1;
  9568. body.forEach(function(stmt, i){
  9569. if (!(stmt instanceof AST_EmptyStatement)) {
  9570. output.indent();
  9571. stmt.print(output);
  9572. if (!(i == last && is_toplevel)) {
  9573. output.newline();
  9574. if (is_toplevel) output.newline();
  9575. }
  9576. }
  9577. });
  9578. };
  9579. AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
  9580. force_statement(this.body, output);
  9581. });
  9582. DEFPRINT(AST_Statement, function(self, output){
  9583. self.body.print(output);
  9584. output.semicolon();
  9585. });
  9586. DEFPRINT(AST_Toplevel, function(self, output){
  9587. display_body(self.body, true, output);
  9588. output.print("");
  9589. });
  9590. DEFPRINT(AST_LabeledStatement, function(self, output){
  9591. self.label.print(output);
  9592. output.colon();
  9593. self.body.print(output);
  9594. });
  9595. DEFPRINT(AST_SimpleStatement, function(self, output){
  9596. self.body.print(output);
  9597. output.semicolon();
  9598. });
  9599. function print_bracketed(body, output) {
  9600. if (body.length > 0) output.with_block(function(){
  9601. display_body(body, false, output);
  9602. });
  9603. else output.print("{}");
  9604. };
  9605. DEFPRINT(AST_BlockStatement, function(self, output){
  9606. print_bracketed(self.body, output);
  9607. });
  9608. DEFPRINT(AST_EmptyStatement, function(self, output){
  9609. output.semicolon();
  9610. });
  9611. DEFPRINT(AST_Do, function(self, output){
  9612. output.print("do");
  9613. output.space();
  9614. self._do_print_body(output);
  9615. output.space();
  9616. output.print("while");
  9617. output.space();
  9618. output.with_parens(function(){
  9619. self.condition.print(output);
  9620. });
  9621. output.semicolon();
  9622. });
  9623. DEFPRINT(AST_While, function(self, output){
  9624. output.print("while");
  9625. output.space();
  9626. output.with_parens(function(){
  9627. self.condition.print(output);
  9628. });
  9629. output.space();
  9630. self._do_print_body(output);
  9631. });
  9632. DEFPRINT(AST_For, function(self, output){
  9633. output.print("for");
  9634. output.space();
  9635. output.with_parens(function(){
  9636. if (self.init) {
  9637. if (self.init instanceof AST_Definitions) {
  9638. self.init.print(output);
  9639. } else {
  9640. parenthesize_for_noin(self.init, output, true);
  9641. }
  9642. output.print(";");
  9643. output.space();
  9644. } else {
  9645. output.print(";");
  9646. }
  9647. if (self.condition) {
  9648. self.condition.print(output);
  9649. output.print(";");
  9650. output.space();
  9651. } else {
  9652. output.print(";");
  9653. }
  9654. if (self.step) {
  9655. self.step.print(output);
  9656. }
  9657. });
  9658. output.space();
  9659. self._do_print_body(output);
  9660. });
  9661. DEFPRINT(AST_ForIn, function(self, output){
  9662. output.print("for");
  9663. output.space();
  9664. output.with_parens(function(){
  9665. self.init.print(output);
  9666. output.space();
  9667. output.print("in");
  9668. output.space();
  9669. self.object.print(output);
  9670. });
  9671. output.space();
  9672. self._do_print_body(output);
  9673. });
  9674. DEFPRINT(AST_With, function(self, output){
  9675. output.print("with");
  9676. output.space();
  9677. output.with_parens(function(){
  9678. self.expression.print(output);
  9679. });
  9680. output.space();
  9681. self._do_print_body(output);
  9682. });
  9683. /* -----[ functions ]----- */
  9684. AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
  9685. var self = this;
  9686. if (!nokeyword) {
  9687. output.print("function");
  9688. }
  9689. if (self.name) {
  9690. output.space();
  9691. self.name.print(output);
  9692. }
  9693. output.with_parens(function(){
  9694. self.argnames.forEach(function(arg, i){
  9695. if (i) output.comma();
  9696. arg.print(output);
  9697. });
  9698. });
  9699. output.space();
  9700. print_bracketed(self.body, output);
  9701. });
  9702. DEFPRINT(AST_Lambda, function(self, output){
  9703. self._do_print(output);
  9704. });
  9705. /* -----[ exits ]----- */
  9706. AST_Exit.DEFMETHOD("_do_print", function(output, kind){
  9707. output.print(kind);
  9708. if (this.value) {
  9709. output.space();
  9710. this.value.print(output);
  9711. }
  9712. output.semicolon();
  9713. });
  9714. DEFPRINT(AST_Return, function(self, output){
  9715. self._do_print(output, "return");
  9716. });
  9717. DEFPRINT(AST_Throw, function(self, output){
  9718. self._do_print(output, "throw");
  9719. });
  9720. /* -----[ loop control ]----- */
  9721. AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
  9722. output.print(kind);
  9723. if (this.label) {
  9724. output.space();
  9725. this.label.print(output);
  9726. }
  9727. output.semicolon();
  9728. });
  9729. DEFPRINT(AST_Break, function(self, output){
  9730. self._do_print(output, "break");
  9731. });
  9732. DEFPRINT(AST_Continue, function(self, output){
  9733. self._do_print(output, "continue");
  9734. });
  9735. /* -----[ if ]----- */
  9736. function make_then(self, output) {
  9737. if (output.option("bracketize")) {
  9738. make_block(self.body, output);
  9739. return;
  9740. }
  9741. // The squeezer replaces "block"-s that contain only a single
  9742. // statement with the statement itself; technically, the AST
  9743. // is correct, but this can create problems when we output an
  9744. // IF having an ELSE clause where the THEN clause ends in an
  9745. // IF *without* an ELSE block (then the outer ELSE would refer
  9746. // to the inner IF). This function checks for this case and
  9747. // adds the block brackets if needed.
  9748. if (!self.body)
  9749. return output.force_semicolon();
  9750. if (self.body instanceof AST_Do
  9751. && !output.option("screw_ie8")) {
  9752. // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
  9753. // croaks with "syntax error" on code like this: if (foo)
  9754. // do ... while(cond); else ... we need block brackets
  9755. // around do/while
  9756. make_block(self.body, output);
  9757. return;
  9758. }
  9759. var b = self.body;
  9760. while (true) {
  9761. if (b instanceof AST_If) {
  9762. if (!b.alternative) {
  9763. make_block(self.body, output);
  9764. return;
  9765. }
  9766. b = b.alternative;
  9767. }
  9768. else if (b instanceof AST_StatementWithBody) {
  9769. b = b.body;
  9770. }
  9771. else break;
  9772. }
  9773. force_statement(self.body, output);
  9774. };
  9775. DEFPRINT(AST_If, function(self, output){
  9776. output.print("if");
  9777. output.space();
  9778. output.with_parens(function(){
  9779. self.condition.print(output);
  9780. });
  9781. output.space();
  9782. if (self.alternative) {
  9783. make_then(self, output);
  9784. output.space();
  9785. output.print("else");
  9786. output.space();
  9787. force_statement(self.alternative, output);
  9788. } else {
  9789. self._do_print_body(output);
  9790. }
  9791. });
  9792. /* -----[ switch ]----- */
  9793. DEFPRINT(AST_Switch, function(self, output){
  9794. output.print("switch");
  9795. output.space();
  9796. output.with_parens(function(){
  9797. self.expression.print(output);
  9798. });
  9799. output.space();
  9800. if (self.body.length > 0) output.with_block(function(){
  9801. self.body.forEach(function(stmt, i){
  9802. if (i) output.newline();
  9803. output.indent(true);
  9804. stmt.print(output);
  9805. });
  9806. });
  9807. else output.print("{}");
  9808. });
  9809. AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
  9810. if (this.body.length > 0) {
  9811. output.newline();
  9812. this.body.forEach(function(stmt){
  9813. output.indent();
  9814. stmt.print(output);
  9815. output.newline();
  9816. });
  9817. }
  9818. });
  9819. DEFPRINT(AST_Default, function(self, output){
  9820. output.print("default:");
  9821. self._do_print_body(output);
  9822. });
  9823. DEFPRINT(AST_Case, function(self, output){
  9824. output.print("case");
  9825. output.space();
  9826. self.expression.print(output);
  9827. output.print(":");
  9828. self._do_print_body(output);
  9829. });
  9830. /* -----[ exceptions ]----- */
  9831. DEFPRINT(AST_Try, function(self, output){
  9832. output.print("try");
  9833. output.space();
  9834. print_bracketed(self.body, output);
  9835. if (self.bcatch) {
  9836. output.space();
  9837. self.bcatch.print(output);
  9838. }
  9839. if (self.bfinally) {
  9840. output.space();
  9841. self.bfinally.print(output);
  9842. }
  9843. });
  9844. DEFPRINT(AST_Catch, function(self, output){
  9845. output.print("catch");
  9846. output.space();
  9847. output.with_parens(function(){
  9848. self.argname.print(output);
  9849. });
  9850. output.space();
  9851. print_bracketed(self.body, output);
  9852. });
  9853. DEFPRINT(AST_Finally, function(self, output){
  9854. output.print("finally");
  9855. output.space();
  9856. print_bracketed(self.body, output);
  9857. });
  9858. /* -----[ var/const ]----- */
  9859. AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
  9860. output.print(kind);
  9861. output.space();
  9862. this.definitions.forEach(function(def, i){
  9863. if (i) output.comma();
  9864. def.print(output);
  9865. });
  9866. var p = output.parent();
  9867. var in_for = p instanceof AST_For || p instanceof AST_ForIn;
  9868. var avoid_semicolon = in_for && p.init === this;
  9869. if (!avoid_semicolon)
  9870. output.semicolon();
  9871. });
  9872. DEFPRINT(AST_Var, function(self, output){
  9873. self._do_print(output, "var");
  9874. });
  9875. DEFPRINT(AST_Const, function(self, output){
  9876. self._do_print(output, "const");
  9877. });
  9878. function parenthesize_for_noin(node, output, noin) {
  9879. if (!noin) node.print(output);
  9880. else try {
  9881. // need to take some precautions here:
  9882. // https://github.com/mishoo/UglifyJS2/issues/60
  9883. node.walk(new TreeWalker(function(node){
  9884. if (node instanceof AST_Binary && node.operator == "in")
  9885. throw output;
  9886. }));
  9887. node.print(output);
  9888. } catch(ex) {
  9889. if (ex !== output) throw ex;
  9890. node.print(output, true);
  9891. }
  9892. };
  9893. DEFPRINT(AST_VarDef, function(self, output){
  9894. self.name.print(output);
  9895. if (self.value) {
  9896. output.space();
  9897. output.print("=");
  9898. output.space();
  9899. var p = output.parent(1);
  9900. var noin = p instanceof AST_For || p instanceof AST_ForIn;
  9901. parenthesize_for_noin(self.value, output, noin);
  9902. }
  9903. });
  9904. /* -----[ other expressions ]----- */
  9905. DEFPRINT(AST_Call, function(self, output){
  9906. self.expression.print(output);
  9907. if (self instanceof AST_New && no_constructor_parens(self, output))
  9908. return;
  9909. output.with_parens(function(){
  9910. self.args.forEach(function(expr, i){
  9911. if (i) output.comma();
  9912. expr.print(output);
  9913. });
  9914. });
  9915. });
  9916. DEFPRINT(AST_New, function(self, output){
  9917. output.print("new");
  9918. output.space();
  9919. AST_Call.prototype._codegen(self, output);
  9920. });
  9921. AST_Seq.DEFMETHOD("_do_print", function(output){
  9922. this.car.print(output);
  9923. if (this.cdr) {
  9924. output.comma();
  9925. if (output.should_break()) {
  9926. output.newline();
  9927. output.indent();
  9928. }
  9929. this.cdr.print(output);
  9930. }
  9931. });
  9932. DEFPRINT(AST_Seq, function(self, output){
  9933. self._do_print(output);
  9934. // var p = output.parent();
  9935. // if (p instanceof AST_Statement) {
  9936. // output.with_indent(output.next_indent(), function(){
  9937. // self._do_print(output);
  9938. // });
  9939. // } else {
  9940. // self._do_print(output);
  9941. // }
  9942. });
  9943. DEFPRINT(AST_Dot, function(self, output){
  9944. var expr = self.expression;
  9945. expr.print(output);
  9946. if (expr instanceof AST_Number && expr.getValue() >= 0) {
  9947. if (!/[xa-f.]/i.test(output.last())) {
  9948. output.print(".");
  9949. }
  9950. }
  9951. output.print(".");
  9952. // the name after dot would be mapped about here.
  9953. output.add_mapping(self.end);
  9954. output.print_name(self.property);
  9955. });
  9956. DEFPRINT(AST_Sub, function(self, output){
  9957. self.expression.print(output);
  9958. output.print("[");
  9959. self.property.print(output);
  9960. output.print("]");
  9961. });
  9962. DEFPRINT(AST_UnaryPrefix, function(self, output){
  9963. var op = self.operator;
  9964. output.print(op);
  9965. if (/^[a-z]/i.test(op))
  9966. output.space();
  9967. self.expression.print(output);
  9968. });
  9969. DEFPRINT(AST_UnaryPostfix, function(self, output){
  9970. self.expression.print(output);
  9971. output.print(self.operator);
  9972. });
  9973. DEFPRINT(AST_Binary, function(self, output){
  9974. self.left.print(output);
  9975. output.space();
  9976. output.print(self.operator);
  9977. if (self.operator == "<"
  9978. && self.right instanceof AST_UnaryPrefix
  9979. && self.right.operator == "!"
  9980. && self.right.expression instanceof AST_UnaryPrefix
  9981. && self.right.expression.operator == "--") {
  9982. // space is mandatory to avoid outputting <!--
  9983. // http://javascript.spec.whatwg.org/#comment-syntax
  9984. output.print(" ");
  9985. } else {
  9986. // the space is optional depending on "beautify"
  9987. output.space();
  9988. }
  9989. self.right.print(output);
  9990. });
  9991. DEFPRINT(AST_Conditional, function(self, output){
  9992. self.condition.print(output);
  9993. output.space();
  9994. output.print("?");
  9995. output.space();
  9996. self.consequent.print(output);
  9997. output.space();
  9998. output.colon();
  9999. self.alternative.print(output);
  10000. });
  10001. /* -----[ literals ]----- */
  10002. DEFPRINT(AST_Array, function(self, output){
  10003. output.with_square(function(){
  10004. var a = self.elements, len = a.length;
  10005. if (len > 0) output.space();
  10006. a.forEach(function(exp, i){
  10007. if (i) output.comma();
  10008. exp.print(output);
  10009. // If the final element is a hole, we need to make sure it
  10010. // doesn't look like a trailing comma, by inserting an actual
  10011. // trailing comma.
  10012. if (i === len - 1 && exp instanceof AST_Hole)
  10013. output.comma();
  10014. });
  10015. if (len > 0) output.space();
  10016. });
  10017. });
  10018. DEFPRINT(AST_Object, function(self, output){
  10019. if (self.properties.length > 0) output.with_block(function(){
  10020. self.properties.forEach(function(prop, i){
  10021. if (i) {
  10022. output.print(",");
  10023. output.newline();
  10024. }
  10025. output.indent();
  10026. prop.print(output);
  10027. });
  10028. output.newline();
  10029. });
  10030. else output.print("{}");
  10031. });
  10032. DEFPRINT(AST_ObjectKeyVal, function(self, output){
  10033. var key = self.key;
  10034. if (output.option("quote_keys")) {
  10035. output.print_string(key + "");
  10036. } else if ((typeof key == "number"
  10037. || !output.option("beautify")
  10038. && +key + "" == key)
  10039. && parseFloat(key) >= 0) {
  10040. output.print(make_num(key));
  10041. } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
  10042. output.print_name(key);
  10043. } else {
  10044. output.print_string(key);
  10045. }
  10046. output.colon();
  10047. self.value.print(output);
  10048. });
  10049. DEFPRINT(AST_ObjectSetter, function(self, output){
  10050. output.print("set");
  10051. output.space();
  10052. self.key.print(output);
  10053. self.value._do_print(output, true);
  10054. });
  10055. DEFPRINT(AST_ObjectGetter, function(self, output){
  10056. output.print("get");
  10057. output.space();
  10058. self.key.print(output);
  10059. self.value._do_print(output, true);
  10060. });
  10061. DEFPRINT(AST_Symbol, function(self, output){
  10062. var def = self.definition();
  10063. output.print_name(def ? def.mangled_name || def.name : self.name);
  10064. });
  10065. DEFPRINT(AST_Undefined, function(self, output){
  10066. output.print("void 0");
  10067. });
  10068. DEFPRINT(AST_Hole, noop);
  10069. DEFPRINT(AST_Infinity, function(self, output){
  10070. output.print("1/0");
  10071. });
  10072. DEFPRINT(AST_NaN, function(self, output){
  10073. output.print("0/0");
  10074. });
  10075. DEFPRINT(AST_This, function(self, output){
  10076. output.print("this");
  10077. });
  10078. DEFPRINT(AST_Constant, function(self, output){
  10079. output.print(self.getValue());
  10080. });
  10081. DEFPRINT(AST_String, function(self, output){
  10082. output.print_string(self.getValue());
  10083. });
  10084. DEFPRINT(AST_Number, function(self, output){
  10085. output.print(make_num(self.getValue()));
  10086. });
  10087. DEFPRINT(AST_RegExp, function(self, output){
  10088. var str = self.getValue().toString();
  10089. if (output.option("ascii_only"))
  10090. str = output.to_ascii(str);
  10091. output.print(str);
  10092. var p = output.parent();
  10093. if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
  10094. output.print(" ");
  10095. });
  10096. function force_statement(stat, output) {
  10097. if (output.option("bracketize")) {
  10098. if (!stat || stat instanceof AST_EmptyStatement)
  10099. output.print("{}");
  10100. else if (stat instanceof AST_BlockStatement)
  10101. stat.print(output);
  10102. else output.with_block(function(){
  10103. output.indent();
  10104. stat.print(output);
  10105. output.newline();
  10106. });
  10107. } else {
  10108. if (!stat || stat instanceof AST_EmptyStatement)
  10109. output.force_semicolon();
  10110. else
  10111. stat.print(output);
  10112. }
  10113. };
  10114. // return true if the node at the top of the stack (that means the
  10115. // innermost node in the current output) is lexically the first in
  10116. // a statement.
  10117. function first_in_statement(output) {
  10118. var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
  10119. while (i > 0) {
  10120. if (p instanceof AST_Statement && p.body === node)
  10121. return true;
  10122. if ((p instanceof AST_Seq && p.car === node ) ||
  10123. (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
  10124. (p instanceof AST_Dot && p.expression === node ) ||
  10125. (p instanceof AST_Sub && p.expression === node ) ||
  10126. (p instanceof AST_Conditional && p.condition === node ) ||
  10127. (p instanceof AST_Binary && p.left === node ) ||
  10128. (p instanceof AST_UnaryPostfix && p.expression === node ))
  10129. {
  10130. node = p;
  10131. p = a[--i];
  10132. } else {
  10133. return false;
  10134. }
  10135. }
  10136. };
  10137. // self should be AST_New. decide if we want to show parens or not.
  10138. function no_constructor_parens(self, output) {
  10139. return self.args.length == 0 && !output.option("beautify");
  10140. };
  10141. function best_of(a) {
  10142. var best = a[0], len = best.length;
  10143. for (var i = 1; i < a.length; ++i) {
  10144. if (a[i].length < len) {
  10145. best = a[i];
  10146. len = best.length;
  10147. }
  10148. }
  10149. return best;
  10150. };
  10151. function make_num(num) {
  10152. var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
  10153. if (Math.floor(num) === num) {
  10154. if (num >= 0) {
  10155. a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
  10156. "0" + num.toString(8)); // same.
  10157. } else {
  10158. a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
  10159. "-0" + (-num).toString(8)); // same.
  10160. }
  10161. if ((m = /^(.*?)(0+)$/.exec(num))) {
  10162. a.push(m[1] + "e" + m[2].length);
  10163. }
  10164. } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
  10165. a.push(m[2] + "e-" + (m[1].length + m[2].length),
  10166. str.substr(str.indexOf(".")));
  10167. }
  10168. return best_of(a);
  10169. };
  10170. function make_block(stmt, output) {
  10171. if (stmt instanceof AST_BlockStatement) {
  10172. stmt.print(output);
  10173. return;
  10174. }
  10175. output.with_block(function(){
  10176. output.indent();
  10177. stmt.print(output);
  10178. output.newline();
  10179. });
  10180. };
  10181. /* -----[ source map generators ]----- */
  10182. function DEFMAP(nodetype, generator) {
  10183. nodetype.DEFMETHOD("add_source_map", function(stream){
  10184. generator(this, stream);
  10185. });
  10186. };
  10187. // We could easily add info for ALL nodes, but it seems to me that
  10188. // would be quite wasteful, hence this noop in the base class.
  10189. DEFMAP(AST_Node, noop);
  10190. function basic_sourcemap_gen(self, output) {
  10191. output.add_mapping(self.start);
  10192. };
  10193. // XXX: I'm not exactly sure if we need it for all of these nodes,
  10194. // or if we should add even more.
  10195. DEFMAP(AST_Directive, basic_sourcemap_gen);
  10196. DEFMAP(AST_Debugger, basic_sourcemap_gen);
  10197. DEFMAP(AST_Symbol, basic_sourcemap_gen);
  10198. DEFMAP(AST_Jump, basic_sourcemap_gen);
  10199. DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
  10200. DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
  10201. DEFMAP(AST_Lambda, basic_sourcemap_gen);
  10202. DEFMAP(AST_Switch, basic_sourcemap_gen);
  10203. DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
  10204. DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
  10205. DEFMAP(AST_Toplevel, noop);
  10206. DEFMAP(AST_New, basic_sourcemap_gen);
  10207. DEFMAP(AST_Try, basic_sourcemap_gen);
  10208. DEFMAP(AST_Catch, basic_sourcemap_gen);
  10209. DEFMAP(AST_Finally, basic_sourcemap_gen);
  10210. DEFMAP(AST_Definitions, basic_sourcemap_gen);
  10211. DEFMAP(AST_Constant, basic_sourcemap_gen);
  10212. DEFMAP(AST_ObjectProperty, function(self, output){
  10213. output.add_mapping(self.start, self.key);
  10214. });
  10215. })();
  10216. /***********************************************************************
  10217. A JavaScript tokenizer / parser / beautifier / compressor.
  10218. https://github.com/mishoo/UglifyJS2
  10219. -------------------------------- (C) ---------------------------------
  10220. Author: Mihai Bazon
  10221. <mihai.bazon@gmail.com>
  10222. http://mihai.bazon.net/blog
  10223. Distributed under the BSD license:
  10224. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  10225. Redistribution and use in source and binary forms, with or without
  10226. modification, are permitted provided that the following conditions
  10227. are met:
  10228. * Redistributions of source code must retain the above
  10229. copyright notice, this list of conditions and the following
  10230. disclaimer.
  10231. * Redistributions in binary form must reproduce the above
  10232. copyright notice, this list of conditions and the following
  10233. disclaimer in the documentation and/or other materials
  10234. provided with the distribution.
  10235. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  10236. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  10237. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  10238. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  10239. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  10240. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  10241. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  10242. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  10243. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  10244. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  10245. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  10246. SUCH DAMAGE.
  10247. ***********************************************************************/
  10248. "use strict";
  10249. function Compressor(options, false_by_default) {
  10250. if (!(this instanceof Compressor))
  10251. return new Compressor(options, false_by_default);
  10252. TreeTransformer.call(this, this.before, this.after);
  10253. this.options = defaults(options, {
  10254. sequences : !false_by_default,
  10255. properties : !false_by_default,
  10256. dead_code : !false_by_default,
  10257. drop_debugger : !false_by_default,
  10258. unsafe : false,
  10259. unsafe_comps : false,
  10260. conditionals : !false_by_default,
  10261. comparisons : !false_by_default,
  10262. evaluate : !false_by_default,
  10263. booleans : !false_by_default,
  10264. loops : !false_by_default,
  10265. unused : !false_by_default,
  10266. hoist_funs : !false_by_default,
  10267. hoist_vars : false,
  10268. if_return : !false_by_default,
  10269. join_vars : !false_by_default,
  10270. cascade : !false_by_default,
  10271. side_effects : !false_by_default,
  10272. pure_getters : false,
  10273. pure_funcs : null,
  10274. negate_iife : !false_by_default,
  10275. screw_ie8 : false,
  10276. drop_console : false,
  10277. warnings : true,
  10278. global_defs : {}
  10279. }, true);
  10280. };
  10281. Compressor.prototype = new TreeTransformer;
  10282. merge(Compressor.prototype, {
  10283. option: function(key) { return this.options[key] },
  10284. warn: function() {
  10285. if (this.options.warnings)
  10286. AST_Node.warn.apply(AST_Node, arguments);
  10287. },
  10288. before: function(node, descend, in_list) {
  10289. if (node._squeezed) return node;
  10290. var was_scope = false;
  10291. if (node instanceof AST_Scope) {
  10292. node = node.hoist_declarations(this);
  10293. was_scope = true;
  10294. }
  10295. descend(node, this);
  10296. node = node.optimize(this);
  10297. if (was_scope && node instanceof AST_Scope) {
  10298. node.drop_unused(this);
  10299. descend(node, this);
  10300. }
  10301. node._squeezed = true;
  10302. return node;
  10303. }
  10304. });
  10305. (function(){
  10306. function OPT(node, optimizer) {
  10307. node.DEFMETHOD("optimize", function(compressor){
  10308. var self = this;
  10309. if (self._optimized) return self;
  10310. var opt = optimizer(self, compressor);
  10311. opt._optimized = true;
  10312. if (opt === self) return opt;
  10313. return opt.transform(compressor);
  10314. });
  10315. };
  10316. OPT(AST_Node, function(self, compressor){
  10317. return self;
  10318. });
  10319. AST_Node.DEFMETHOD("equivalent_to", function(node){
  10320. // XXX: this is a rather expensive way to test two node's equivalence:
  10321. return this.print_to_string() == node.print_to_string();
  10322. });
  10323. function make_node(ctor, orig, props) {
  10324. if (!props) props = {};
  10325. if (orig) {
  10326. if (!props.start) props.start = orig.start;
  10327. if (!props.end) props.end = orig.end;
  10328. }
  10329. return new ctor(props);
  10330. };
  10331. function make_node_from_constant(compressor, val, orig) {
  10332. // XXX: WIP.
  10333. // if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){
  10334. // if (node instanceof AST_SymbolRef) {
  10335. // var scope = compressor.find_parent(AST_Scope);
  10336. // var def = scope.find_variable(node);
  10337. // node.thedef = def;
  10338. // return node;
  10339. // }
  10340. // })).transform(compressor);
  10341. if (val instanceof AST_Node) return val.transform(compressor);
  10342. switch (typeof val) {
  10343. case "string":
  10344. return make_node(AST_String, orig, {
  10345. value: val
  10346. }).optimize(compressor);
  10347. case "number":
  10348. return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
  10349. value: val
  10350. }).optimize(compressor);
  10351. case "boolean":
  10352. return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
  10353. case "undefined":
  10354. return make_node(AST_Undefined, orig).optimize(compressor);
  10355. default:
  10356. if (val === null) {
  10357. return make_node(AST_Null, orig).optimize(compressor);
  10358. }
  10359. if (val instanceof RegExp) {
  10360. return make_node(AST_RegExp, orig).optimize(compressor);
  10361. }
  10362. throw new Error(string_template("Can't handle constant of type: {type}", {
  10363. type: typeof val
  10364. }));
  10365. }
  10366. };
  10367. function as_statement_array(thing) {
  10368. if (thing === null) return [];
  10369. if (thing instanceof AST_BlockStatement) return thing.body;
  10370. if (thing instanceof AST_EmptyStatement) return [];
  10371. if (thing instanceof AST_Statement) return [ thing ];
  10372. throw new Error("Can't convert thing to statement array");
  10373. };
  10374. function is_empty(thing) {
  10375. if (thing === null) return true;
  10376. if (thing instanceof AST_EmptyStatement) return true;
  10377. if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
  10378. return false;
  10379. };
  10380. function loop_body(x) {
  10381. if (x instanceof AST_Switch) return x;
  10382. if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
  10383. return (x.body instanceof AST_BlockStatement ? x.body : x);
  10384. }
  10385. return x;
  10386. };
  10387. function tighten_body(statements, compressor) {
  10388. var CHANGED;
  10389. do {
  10390. CHANGED = false;
  10391. statements = eliminate_spurious_blocks(statements);
  10392. if (compressor.option("dead_code")) {
  10393. statements = eliminate_dead_code(statements, compressor);
  10394. }
  10395. if (compressor.option("if_return")) {
  10396. statements = handle_if_return(statements, compressor);
  10397. }
  10398. if (compressor.option("sequences")) {
  10399. statements = sequencesize(statements, compressor);
  10400. }
  10401. if (compressor.option("join_vars")) {
  10402. statements = join_consecutive_vars(statements, compressor);
  10403. }
  10404. } while (CHANGED);
  10405. if (compressor.option("negate_iife")) {
  10406. negate_iifes(statements, compressor);
  10407. }
  10408. return statements;
  10409. function eliminate_spurious_blocks(statements) {
  10410. var seen_dirs = [];
  10411. return statements.reduce(function(a, stat){
  10412. if (stat instanceof AST_BlockStatement) {
  10413. CHANGED = true;
  10414. a.push.apply(a, eliminate_spurious_blocks(stat.body));
  10415. } else if (stat instanceof AST_EmptyStatement) {
  10416. CHANGED = true;
  10417. } else if (stat instanceof AST_Directive) {
  10418. if (seen_dirs.indexOf(stat.value) < 0) {
  10419. a.push(stat);
  10420. seen_dirs.push(stat.value);
  10421. } else {
  10422. CHANGED = true;
  10423. }
  10424. } else {
  10425. a.push(stat);
  10426. }
  10427. return a;
  10428. }, []);
  10429. };
  10430. function handle_if_return(statements, compressor) {
  10431. var self = compressor.self();
  10432. var in_lambda = self instanceof AST_Lambda;
  10433. var ret = [];
  10434. loop: for (var i = statements.length; --i >= 0;) {
  10435. var stat = statements[i];
  10436. switch (true) {
  10437. case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
  10438. CHANGED = true;
  10439. // note, ret.length is probably always zero
  10440. // because we drop unreachable code before this
  10441. // step. nevertheless, it's good to check.
  10442. continue loop;
  10443. case stat instanceof AST_If:
  10444. if (stat.body instanceof AST_Return) {
  10445. //---
  10446. // pretty silly case, but:
  10447. // if (foo()) return; return; ==> foo(); return;
  10448. if (((in_lambda && ret.length == 0)
  10449. || (ret[0] instanceof AST_Return && !ret[0].value))
  10450. && !stat.body.value && !stat.alternative) {
  10451. CHANGED = true;
  10452. var cond = make_node(AST_SimpleStatement, stat.condition, {
  10453. body: stat.condition
  10454. });
  10455. ret.unshift(cond);
  10456. continue loop;
  10457. }
  10458. //---
  10459. // if (foo()) return x; return y; ==> return foo() ? x : y;
  10460. if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
  10461. CHANGED = true;
  10462. stat = stat.clone();
  10463. stat.alternative = ret[0];
  10464. ret[0] = stat.transform(compressor);
  10465. continue loop;
  10466. }
  10467. //---
  10468. // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
  10469. if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
  10470. CHANGED = true;
  10471. stat = stat.clone();
  10472. stat.alternative = ret[0] || make_node(AST_Return, stat, {
  10473. value: make_node(AST_Undefined, stat)
  10474. });
  10475. ret[0] = stat.transform(compressor);
  10476. continue loop;
  10477. }
  10478. //---
  10479. // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
  10480. if (!stat.body.value && in_lambda) {
  10481. CHANGED = true;
  10482. stat = stat.clone();
  10483. stat.condition = stat.condition.negate(compressor);
  10484. stat.body = make_node(AST_BlockStatement, stat, {
  10485. body: as_statement_array(stat.alternative).concat(ret)
  10486. });
  10487. stat.alternative = null;
  10488. ret = [ stat.transform(compressor) ];
  10489. continue loop;
  10490. }
  10491. //---
  10492. if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
  10493. && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
  10494. CHANGED = true;
  10495. ret.push(make_node(AST_Return, ret[0], {
  10496. value: make_node(AST_Undefined, ret[0])
  10497. }).transform(compressor));
  10498. ret = as_statement_array(stat.alternative).concat(ret);
  10499. ret.unshift(stat);
  10500. continue loop;
  10501. }
  10502. }
  10503. var ab = aborts(stat.body);
  10504. var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
  10505. if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
  10506. || (ab instanceof AST_Continue && self === loop_body(lct))
  10507. || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
  10508. if (ab.label) {
  10509. remove(ab.label.thedef.references, ab);
  10510. }
  10511. CHANGED = true;
  10512. var body = as_statement_array(stat.body).slice(0, -1);
  10513. stat = stat.clone();
  10514. stat.condition = stat.condition.negate(compressor);
  10515. stat.body = make_node(AST_BlockStatement, stat, {
  10516. body: ret
  10517. });
  10518. stat.alternative = make_node(AST_BlockStatement, stat, {
  10519. body: body
  10520. });
  10521. ret = [ stat.transform(compressor) ];
  10522. continue loop;
  10523. }
  10524. var ab = aborts(stat.alternative);
  10525. var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
  10526. if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
  10527. || (ab instanceof AST_Continue && self === loop_body(lct))
  10528. || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
  10529. if (ab.label) {
  10530. remove(ab.label.thedef.references, ab);
  10531. }
  10532. CHANGED = true;
  10533. stat = stat.clone();
  10534. stat.body = make_node(AST_BlockStatement, stat.body, {
  10535. body: as_statement_array(stat.body).concat(ret)
  10536. });
  10537. stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
  10538. body: as_statement_array(stat.alternative).slice(0, -1)
  10539. });
  10540. ret = [ stat.transform(compressor) ];
  10541. continue loop;
  10542. }
  10543. ret.unshift(stat);
  10544. break;
  10545. default:
  10546. ret.unshift(stat);
  10547. break;
  10548. }
  10549. }
  10550. return ret;
  10551. };
  10552. function eliminate_dead_code(statements, compressor) {
  10553. var has_quit = false;
  10554. var orig = statements.length;
  10555. var self = compressor.self();
  10556. statements = statements.reduce(function(a, stat){
  10557. if (has_quit) {
  10558. extract_declarations_from_unreachable_code(compressor, stat, a);
  10559. } else {
  10560. if (stat instanceof AST_LoopControl) {
  10561. var lct = compressor.loopcontrol_target(stat.label);
  10562. if ((stat instanceof AST_Break
  10563. && lct instanceof AST_BlockStatement
  10564. && loop_body(lct) === self) || (stat instanceof AST_Continue
  10565. && loop_body(lct) === self)) {
  10566. if (stat.label) {
  10567. remove(stat.label.thedef.references, stat);
  10568. }
  10569. } else {
  10570. a.push(stat);
  10571. }
  10572. } else {
  10573. a.push(stat);
  10574. }
  10575. if (aborts(stat)) has_quit = true;
  10576. }
  10577. return a;
  10578. }, []);
  10579. CHANGED = statements.length != orig;
  10580. return statements;
  10581. };
  10582. function sequencesize(statements, compressor) {
  10583. if (statements.length < 2) return statements;
  10584. var seq = [], ret = [];
  10585. function push_seq() {
  10586. seq = AST_Seq.from_array(seq);
  10587. if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
  10588. body: seq
  10589. }));
  10590. seq = [];
  10591. };
  10592. statements.forEach(function(stat){
  10593. if (stat instanceof AST_SimpleStatement) seq.push(stat.body);
  10594. else push_seq(), ret.push(stat);
  10595. });
  10596. push_seq();
  10597. ret = sequencesize_2(ret, compressor);
  10598. CHANGED = ret.length != statements.length;
  10599. return ret;
  10600. };
  10601. function sequencesize_2(statements, compressor) {
  10602. function cons_seq(right) {
  10603. ret.pop();
  10604. var left = prev.body;
  10605. if (left instanceof AST_Seq) {
  10606. left.add(right);
  10607. } else {
  10608. left = AST_Seq.cons(left, right);
  10609. }
  10610. return left.transform(compressor);
  10611. };
  10612. var ret = [], prev = null;
  10613. statements.forEach(function(stat){
  10614. if (prev) {
  10615. if (stat instanceof AST_For) {
  10616. var opera = {};
  10617. try {
  10618. prev.body.walk(new TreeWalker(function(node){
  10619. if (node instanceof AST_Binary && node.operator == "in")
  10620. throw opera;
  10621. }));
  10622. if (stat.init && !(stat.init instanceof AST_Definitions)) {
  10623. stat.init = cons_seq(stat.init);
  10624. }
  10625. else if (!stat.init) {
  10626. stat.init = prev.body;
  10627. ret.pop();
  10628. }
  10629. } catch(ex) {
  10630. if (ex !== opera) throw ex;
  10631. }
  10632. }
  10633. else if (stat instanceof AST_If) {
  10634. stat.condition = cons_seq(stat.condition);
  10635. }
  10636. else if (stat instanceof AST_With) {
  10637. stat.expression = cons_seq(stat.expression);
  10638. }
  10639. else if (stat instanceof AST_Exit && stat.value) {
  10640. stat.value = cons_seq(stat.value);
  10641. }
  10642. else if (stat instanceof AST_Exit) {
  10643. stat.value = cons_seq(make_node(AST_Undefined, stat));
  10644. }
  10645. else if (stat instanceof AST_Switch) {
  10646. stat.expression = cons_seq(stat.expression);
  10647. }
  10648. }
  10649. ret.push(stat);
  10650. prev = stat instanceof AST_SimpleStatement ? stat : null;
  10651. });
  10652. return ret;
  10653. };
  10654. function join_consecutive_vars(statements, compressor) {
  10655. var prev = null;
  10656. return statements.reduce(function(a, stat){
  10657. if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
  10658. prev.definitions = prev.definitions.concat(stat.definitions);
  10659. CHANGED = true;
  10660. }
  10661. else if (stat instanceof AST_For
  10662. && prev instanceof AST_Definitions
  10663. && (!stat.init || stat.init.TYPE == prev.TYPE)) {
  10664. CHANGED = true;
  10665. a.pop();
  10666. if (stat.init) {
  10667. stat.init.definitions = prev.definitions.concat(stat.init.definitions);
  10668. } else {
  10669. stat.init = prev;
  10670. }
  10671. a.push(stat);
  10672. prev = stat;
  10673. }
  10674. else {
  10675. prev = stat;
  10676. a.push(stat);
  10677. }
  10678. return a;
  10679. }, []);
  10680. };
  10681. function negate_iifes(statements, compressor) {
  10682. statements.forEach(function(stat){
  10683. if (stat instanceof AST_SimpleStatement) {
  10684. stat.body = (function transform(thing) {
  10685. return thing.transform(new TreeTransformer(function(node){
  10686. if (node instanceof AST_Call && node.expression instanceof AST_Function) {
  10687. return make_node(AST_UnaryPrefix, node, {
  10688. operator: "!",
  10689. expression: node
  10690. });
  10691. }
  10692. else if (node instanceof AST_Call) {
  10693. node.expression = transform(node.expression);
  10694. }
  10695. else if (node instanceof AST_Seq) {
  10696. node.car = transform(node.car);
  10697. }
  10698. else if (node instanceof AST_Conditional) {
  10699. var expr = transform(node.condition);
  10700. if (expr !== node.condition) {
  10701. // it has been negated, reverse
  10702. node.condition = expr;
  10703. var tmp = node.consequent;
  10704. node.consequent = node.alternative;
  10705. node.alternative = tmp;
  10706. }
  10707. }
  10708. return node;
  10709. }));
  10710. })(stat.body);
  10711. }
  10712. });
  10713. };
  10714. };
  10715. function extract_declarations_from_unreachable_code(compressor, stat, target) {
  10716. compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
  10717. stat.walk(new TreeWalker(function(node){
  10718. if (node instanceof AST_Definitions) {
  10719. compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
  10720. node.remove_initializers();
  10721. target.push(node);
  10722. return true;
  10723. }
  10724. if (node instanceof AST_Defun) {
  10725. target.push(node);
  10726. return true;
  10727. }
  10728. if (node instanceof AST_Scope) {
  10729. return true;
  10730. }
  10731. }));
  10732. };
  10733. /* -----[ boolean/negation helpers ]----- */
  10734. // methods to determine whether an expression has a boolean result type
  10735. (function (def){
  10736. var unary_bool = [ "!", "delete" ];
  10737. var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
  10738. def(AST_Node, function(){ return false });
  10739. def(AST_UnaryPrefix, function(){
  10740. return member(this.operator, unary_bool);
  10741. });
  10742. def(AST_Binary, function(){
  10743. return member(this.operator, binary_bool) ||
  10744. ( (this.operator == "&&" || this.operator == "||") &&
  10745. this.left.is_boolean() && this.right.is_boolean() );
  10746. });
  10747. def(AST_Conditional, function(){
  10748. return this.consequent.is_boolean() && this.alternative.is_boolean();
  10749. });
  10750. def(AST_Assign, function(){
  10751. return this.operator == "=" && this.right.is_boolean();
  10752. });
  10753. def(AST_Seq, function(){
  10754. return this.cdr.is_boolean();
  10755. });
  10756. def(AST_True, function(){ return true });
  10757. def(AST_False, function(){ return true });
  10758. })(function(node, func){
  10759. node.DEFMETHOD("is_boolean", func);
  10760. });
  10761. // methods to determine if an expression has a string result type
  10762. (function (def){
  10763. def(AST_Node, function(){ return false });
  10764. def(AST_String, function(){ return true });
  10765. def(AST_UnaryPrefix, function(){
  10766. return this.operator == "typeof";
  10767. });
  10768. def(AST_Binary, function(compressor){
  10769. return this.operator == "+" &&
  10770. (this.left.is_string(compressor) || this.right.is_string(compressor));
  10771. });
  10772. def(AST_Assign, function(compressor){
  10773. return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
  10774. });
  10775. def(AST_Seq, function(compressor){
  10776. return this.cdr.is_string(compressor);
  10777. });
  10778. def(AST_Conditional, function(compressor){
  10779. return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
  10780. });
  10781. def(AST_Call, function(compressor){
  10782. return compressor.option("unsafe")
  10783. && this.expression instanceof AST_SymbolRef
  10784. && this.expression.name == "String"
  10785. && this.expression.undeclared();
  10786. });
  10787. })(function(node, func){
  10788. node.DEFMETHOD("is_string", func);
  10789. });
  10790. function best_of(ast1, ast2) {
  10791. return ast1.print_to_string().length >
  10792. ast2.print_to_string().length
  10793. ? ast2 : ast1;
  10794. };
  10795. // methods to evaluate a constant expression
  10796. (function (def){
  10797. // The evaluate method returns an array with one or two
  10798. // elements. If the node has been successfully reduced to a
  10799. // constant, then the second element tells us the value;
  10800. // otherwise the second element is missing. The first element
  10801. // of the array is always an AST_Node descendant; if
  10802. // evaluation was successful it's a node that represents the
  10803. // constant; otherwise it's the original or a replacement node.
  10804. AST_Node.DEFMETHOD("evaluate", function(compressor){
  10805. if (!compressor.option("evaluate")) return [ this ];
  10806. try {
  10807. var val = this._eval(compressor);
  10808. return [ best_of(make_node_from_constant(compressor, val, this), this), val ];
  10809. } catch(ex) {
  10810. if (ex !== def) throw ex;
  10811. return [ this ];
  10812. }
  10813. });
  10814. def(AST_Statement, function(){
  10815. throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
  10816. });
  10817. def(AST_Function, function(){
  10818. // XXX: AST_Function inherits from AST_Scope, which itself
  10819. // inherits from AST_Statement; however, an AST_Function
  10820. // isn't really a statement. This could byte in other
  10821. // places too. :-( Wish JS had multiple inheritance.
  10822. throw def;
  10823. });
  10824. function ev(node, compressor) {
  10825. if (!compressor) throw new Error("Compressor must be passed");
  10826. return node._eval(compressor);
  10827. };
  10828. def(AST_Node, function(){
  10829. throw def; // not constant
  10830. });
  10831. def(AST_Constant, function(){
  10832. return this.getValue();
  10833. });
  10834. def(AST_UnaryPrefix, function(compressor){
  10835. var e = this.expression;
  10836. switch (this.operator) {
  10837. case "!": return !ev(e, compressor);
  10838. case "typeof":
  10839. // Function would be evaluated to an array and so typeof would
  10840. // incorrectly return 'object'. Hence making is a special case.
  10841. if (e instanceof AST_Function) return typeof function(){};
  10842. e = ev(e, compressor);
  10843. // typeof <RegExp> returns "object" or "function" on different platforms
  10844. // so cannot evaluate reliably
  10845. if (e instanceof RegExp) throw def;
  10846. return typeof e;
  10847. case "void": return void ev(e, compressor);
  10848. case "~": return ~ev(e, compressor);
  10849. case "-":
  10850. e = ev(e, compressor);
  10851. if (e === 0) throw def;
  10852. return -e;
  10853. case "+": return +ev(e, compressor);
  10854. }
  10855. throw def;
  10856. });
  10857. def(AST_Binary, function(c){
  10858. var left = this.left, right = this.right;
  10859. switch (this.operator) {
  10860. case "&&" : return ev(left, c) && ev(right, c);
  10861. case "||" : return ev(left, c) || ev(right, c);
  10862. case "|" : return ev(left, c) | ev(right, c);
  10863. case "&" : return ev(left, c) & ev(right, c);
  10864. case "^" : return ev(left, c) ^ ev(right, c);
  10865. case "+" : return ev(left, c) + ev(right, c);
  10866. case "*" : return ev(left, c) * ev(right, c);
  10867. case "/" : return ev(left, c) / ev(right, c);
  10868. case "%" : return ev(left, c) % ev(right, c);
  10869. case "-" : return ev(left, c) - ev(right, c);
  10870. case "<<" : return ev(left, c) << ev(right, c);
  10871. case ">>" : return ev(left, c) >> ev(right, c);
  10872. case ">>>" : return ev(left, c) >>> ev(right, c);
  10873. case "==" : return ev(left, c) == ev(right, c);
  10874. case "===" : return ev(left, c) === ev(right, c);
  10875. case "!=" : return ev(left, c) != ev(right, c);
  10876. case "!==" : return ev(left, c) !== ev(right, c);
  10877. case "<" : return ev(left, c) < ev(right, c);
  10878. case "<=" : return ev(left, c) <= ev(right, c);
  10879. case ">" : return ev(left, c) > ev(right, c);
  10880. case ">=" : return ev(left, c) >= ev(right, c);
  10881. case "in" : return ev(left, c) in ev(right, c);
  10882. case "instanceof" : return ev(left, c) instanceof ev(right, c);
  10883. }
  10884. throw def;
  10885. });
  10886. def(AST_Conditional, function(compressor){
  10887. return ev(this.condition, compressor)
  10888. ? ev(this.consequent, compressor)
  10889. : ev(this.alternative, compressor);
  10890. });
  10891. def(AST_SymbolRef, function(compressor){
  10892. var d = this.definition();
  10893. if (d && d.constant && d.init) return ev(d.init, compressor);
  10894. throw def;
  10895. });
  10896. })(function(node, func){
  10897. node.DEFMETHOD("_eval", func);
  10898. });
  10899. // method to negate an expression
  10900. (function(def){
  10901. function basic_negation(exp) {
  10902. return make_node(AST_UnaryPrefix, exp, {
  10903. operator: "!",
  10904. expression: exp
  10905. });
  10906. };
  10907. def(AST_Node, function(){
  10908. return basic_negation(this);
  10909. });
  10910. def(AST_Statement, function(){
  10911. throw new Error("Cannot negate a statement");
  10912. });
  10913. def(AST_Function, function(){
  10914. return basic_negation(this);
  10915. });
  10916. def(AST_UnaryPrefix, function(){
  10917. if (this.operator == "!")
  10918. return this.expression;
  10919. return basic_negation(this);
  10920. });
  10921. def(AST_Seq, function(compressor){
  10922. var self = this.clone();
  10923. self.cdr = self.cdr.negate(compressor);
  10924. return self;
  10925. });
  10926. def(AST_Conditional, function(compressor){
  10927. var self = this.clone();
  10928. self.consequent = self.consequent.negate(compressor);
  10929. self.alternative = self.alternative.negate(compressor);
  10930. return best_of(basic_negation(this), self);
  10931. });
  10932. def(AST_Binary, function(compressor){
  10933. var self = this.clone(), op = this.operator;
  10934. if (compressor.option("unsafe_comps")) {
  10935. switch (op) {
  10936. case "<=" : self.operator = ">" ; return self;
  10937. case "<" : self.operator = ">=" ; return self;
  10938. case ">=" : self.operator = "<" ; return self;
  10939. case ">" : self.operator = "<=" ; return self;
  10940. }
  10941. }
  10942. switch (op) {
  10943. case "==" : self.operator = "!="; return self;
  10944. case "!=" : self.operator = "=="; return self;
  10945. case "===": self.operator = "!=="; return self;
  10946. case "!==": self.operator = "==="; return self;
  10947. case "&&":
  10948. self.operator = "||";
  10949. self.left = self.left.negate(compressor);
  10950. self.right = self.right.negate(compressor);
  10951. return best_of(basic_negation(this), self);
  10952. case "||":
  10953. self.operator = "&&";
  10954. self.left = self.left.negate(compressor);
  10955. self.right = self.right.negate(compressor);
  10956. return best_of(basic_negation(this), self);
  10957. }
  10958. return basic_negation(this);
  10959. });
  10960. })(function(node, func){
  10961. node.DEFMETHOD("negate", function(compressor){
  10962. return func.call(this, compressor);
  10963. });
  10964. });
  10965. // determine if expression has side effects
  10966. (function(def){
  10967. def(AST_Node, function(compressor){ return true });
  10968. def(AST_EmptyStatement, function(compressor){ return false });
  10969. def(AST_Constant, function(compressor){ return false });
  10970. def(AST_This, function(compressor){ return false });
  10971. def(AST_Call, function(compressor){
  10972. var pure = compressor.option("pure_funcs");
  10973. if (!pure) return true;
  10974. return pure.indexOf(this.expression.print_to_string()) < 0;
  10975. });
  10976. def(AST_Block, function(compressor){
  10977. for (var i = this.body.length; --i >= 0;) {
  10978. if (this.body[i].has_side_effects(compressor))
  10979. return true;
  10980. }
  10981. return false;
  10982. });
  10983. def(AST_SimpleStatement, function(compressor){
  10984. return this.body.has_side_effects(compressor);
  10985. });
  10986. def(AST_Defun, function(compressor){ return true });
  10987. def(AST_Function, function(compressor){ return false });
  10988. def(AST_Binary, function(compressor){
  10989. return this.left.has_side_effects(compressor)
  10990. || this.right.has_side_effects(compressor);
  10991. });
  10992. def(AST_Assign, function(compressor){ return true });
  10993. def(AST_Conditional, function(compressor){
  10994. return this.condition.has_side_effects(compressor)
  10995. || this.consequent.has_side_effects(compressor)
  10996. || this.alternative.has_side_effects(compressor);
  10997. });
  10998. def(AST_Unary, function(compressor){
  10999. return this.operator == "delete"
  11000. || this.operator == "++"
  11001. || this.operator == "--"
  11002. || this.expression.has_side_effects(compressor);
  11003. });
  11004. def(AST_SymbolRef, function(compressor){ return false });
  11005. def(AST_Object, function(compressor){
  11006. for (var i = this.properties.length; --i >= 0;)
  11007. if (this.properties[i].has_side_effects(compressor))
  11008. return true;
  11009. return false;
  11010. });
  11011. def(AST_ObjectProperty, function(compressor){
  11012. return this.value.has_side_effects(compressor);
  11013. });
  11014. def(AST_Array, function(compressor){
  11015. for (var i = this.elements.length; --i >= 0;)
  11016. if (this.elements[i].has_side_effects(compressor))
  11017. return true;
  11018. return false;
  11019. });
  11020. def(AST_Dot, function(compressor){
  11021. if (!compressor.option("pure_getters")) return true;
  11022. return this.expression.has_side_effects(compressor);
  11023. });
  11024. def(AST_Sub, function(compressor){
  11025. if (!compressor.option("pure_getters")) return true;
  11026. return this.expression.has_side_effects(compressor)
  11027. || this.property.has_side_effects(compressor);
  11028. });
  11029. def(AST_PropAccess, function(compressor){
  11030. return !compressor.option("pure_getters");
  11031. });
  11032. def(AST_Seq, function(compressor){
  11033. return this.car.has_side_effects(compressor)
  11034. || this.cdr.has_side_effects(compressor);
  11035. });
  11036. })(function(node, func){
  11037. node.DEFMETHOD("has_side_effects", func);
  11038. });
  11039. // tell me if a statement aborts
  11040. function aborts(thing) {
  11041. return thing && thing.aborts();
  11042. };
  11043. (function(def){
  11044. def(AST_Statement, function(){ return null });
  11045. def(AST_Jump, function(){ return this });
  11046. function block_aborts(){
  11047. var n = this.body.length;
  11048. return n > 0 && aborts(this.body[n - 1]);
  11049. };
  11050. def(AST_BlockStatement, block_aborts);
  11051. def(AST_SwitchBranch, block_aborts);
  11052. def(AST_If, function(){
  11053. return this.alternative && aborts(this.body) && aborts(this.alternative);
  11054. });
  11055. })(function(node, func){
  11056. node.DEFMETHOD("aborts", func);
  11057. });
  11058. /* -----[ optimizers ]----- */
  11059. OPT(AST_Directive, function(self, compressor){
  11060. if (self.scope.has_directive(self.value) !== self.scope) {
  11061. return make_node(AST_EmptyStatement, self);
  11062. }
  11063. return self;
  11064. });
  11065. OPT(AST_Debugger, function(self, compressor){
  11066. if (compressor.option("drop_debugger"))
  11067. return make_node(AST_EmptyStatement, self);
  11068. return self;
  11069. });
  11070. OPT(AST_LabeledStatement, function(self, compressor){
  11071. if (self.body instanceof AST_Break
  11072. && compressor.loopcontrol_target(self.body.label) === self.body) {
  11073. return make_node(AST_EmptyStatement, self);
  11074. }
  11075. return self.label.references.length == 0 ? self.body : self;
  11076. });
  11077. OPT(AST_Block, function(self, compressor){
  11078. self.body = tighten_body(self.body, compressor);
  11079. return self;
  11080. });
  11081. OPT(AST_BlockStatement, function(self, compressor){
  11082. self.body = tighten_body(self.body, compressor);
  11083. switch (self.body.length) {
  11084. case 1: return self.body[0];
  11085. case 0: return make_node(AST_EmptyStatement, self);
  11086. }
  11087. return self;
  11088. });
  11089. AST_Scope.DEFMETHOD("drop_unused", function(compressor){
  11090. var self = this;
  11091. if (compressor.option("unused")
  11092. && !(self instanceof AST_Toplevel)
  11093. && !self.uses_eval
  11094. ) {
  11095. var in_use = [];
  11096. var initializations = new Dictionary();
  11097. // pass 1: find out which symbols are directly used in
  11098. // this scope (not in nested scopes).
  11099. var scope = this;
  11100. var tw = new TreeWalker(function(node, descend){
  11101. if (node !== self) {
  11102. if (node instanceof AST_Defun) {
  11103. initializations.add(node.name.name, node);
  11104. return true; // don't go in nested scopes
  11105. }
  11106. if (node instanceof AST_Definitions && scope === self) {
  11107. node.definitions.forEach(function(def){
  11108. if (def.value) {
  11109. initializations.add(def.name.name, def.value);
  11110. if (def.value.has_side_effects(compressor)) {
  11111. def.value.walk(tw);
  11112. }
  11113. }
  11114. });
  11115. return true;
  11116. }
  11117. if (node instanceof AST_SymbolRef) {
  11118. push_uniq(in_use, node.definition());
  11119. return true;
  11120. }
  11121. if (node instanceof AST_Scope) {
  11122. var save_scope = scope;
  11123. scope = node;
  11124. descend();
  11125. scope = save_scope;
  11126. return true;
  11127. }
  11128. }
  11129. });
  11130. self.walk(tw);
  11131. // pass 2: for every used symbol we need to walk its
  11132. // initialization code to figure out if it uses other
  11133. // symbols (that may not be in_use).
  11134. for (var i = 0; i < in_use.length; ++i) {
  11135. in_use[i].orig.forEach(function(decl){
  11136. // undeclared globals will be instanceof AST_SymbolRef
  11137. var init = initializations.get(decl.name);
  11138. if (init) init.forEach(function(init){
  11139. var tw = new TreeWalker(function(node){
  11140. if (node instanceof AST_SymbolRef) {
  11141. push_uniq(in_use, node.definition());
  11142. }
  11143. });
  11144. init.walk(tw);
  11145. });
  11146. });
  11147. }
  11148. // pass 3: we should drop declarations not in_use
  11149. var tt = new TreeTransformer(
  11150. function before(node, descend, in_list) {
  11151. if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
  11152. for (var a = node.argnames, i = a.length; --i >= 0;) {
  11153. var sym = a[i];
  11154. if (sym.unreferenced()) {
  11155. a.pop();
  11156. compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
  11157. name : sym.name,
  11158. file : sym.start.file,
  11159. line : sym.start.line,
  11160. col : sym.start.col
  11161. });
  11162. }
  11163. else break;
  11164. }
  11165. }
  11166. if (node instanceof AST_Defun && node !== self) {
  11167. if (!member(node.name.definition(), in_use)) {
  11168. compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
  11169. name : node.name.name,
  11170. file : node.name.start.file,
  11171. line : node.name.start.line,
  11172. col : node.name.start.col
  11173. });
  11174. return make_node(AST_EmptyStatement, node);
  11175. }
  11176. return node;
  11177. }
  11178. if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
  11179. var def = node.definitions.filter(function(def){
  11180. if (member(def.name.definition(), in_use)) return true;
  11181. var w = {
  11182. name : def.name.name,
  11183. file : def.name.start.file,
  11184. line : def.name.start.line,
  11185. col : def.name.start.col
  11186. };
  11187. if (def.value && def.value.has_side_effects(compressor)) {
  11188. def._unused_side_effects = true;
  11189. compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
  11190. return true;
  11191. }
  11192. compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);
  11193. return false;
  11194. });
  11195. // place uninitialized names at the start
  11196. def = mergeSort(def, function(a, b){
  11197. if (!a.value && b.value) return -1;
  11198. if (!b.value && a.value) return 1;
  11199. return 0;
  11200. });
  11201. // for unused names whose initialization has
  11202. // side effects, we can cascade the init. code
  11203. // into the next one, or next statement.
  11204. var side_effects = [];
  11205. for (var i = 0; i < def.length;) {
  11206. var x = def[i];
  11207. if (x._unused_side_effects) {
  11208. side_effects.push(x.value);
  11209. def.splice(i, 1);
  11210. } else {
  11211. if (side_effects.length > 0) {
  11212. side_effects.push(x.value);
  11213. x.value = AST_Seq.from_array(side_effects);
  11214. side_effects = [];
  11215. }
  11216. ++i;
  11217. }
  11218. }
  11219. if (side_effects.length > 0) {
  11220. side_effects = make_node(AST_BlockStatement, node, {
  11221. body: [ make_node(AST_SimpleStatement, node, {
  11222. body: AST_Seq.from_array(side_effects)
  11223. }) ]
  11224. });
  11225. } else {
  11226. side_effects = null;
  11227. }
  11228. if (def.length == 0 && !side_effects) {
  11229. return make_node(AST_EmptyStatement, node);
  11230. }
  11231. if (def.length == 0) {
  11232. return side_effects;
  11233. }
  11234. node.definitions = def;
  11235. if (side_effects) {
  11236. side_effects.body.unshift(node);
  11237. node = side_effects;
  11238. }
  11239. return node;
  11240. }
  11241. if (node instanceof AST_For) {
  11242. descend(node, this);
  11243. if (node.init instanceof AST_BlockStatement) {
  11244. // certain combination of unused name + side effect leads to:
  11245. // https://github.com/mishoo/UglifyJS2/issues/44
  11246. // that's an invalid AST.
  11247. // We fix it at this stage by moving the `var` outside the `for`.
  11248. var body = node.init.body.slice(0, -1);
  11249. node.init = node.init.body.slice(-1)[0].body;
  11250. body.push(node);
  11251. return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
  11252. body: body
  11253. });
  11254. }
  11255. }
  11256. if (node instanceof AST_Scope && node !== self)
  11257. return node;
  11258. }
  11259. );
  11260. self.transform(tt);
  11261. }
  11262. });
  11263. AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
  11264. var hoist_funs = compressor.option("hoist_funs");
  11265. var hoist_vars = compressor.option("hoist_vars");
  11266. var self = this;
  11267. if (hoist_funs || hoist_vars) {
  11268. var dirs = [];
  11269. var hoisted = [];
  11270. var vars = new Dictionary(), vars_found = 0, var_decl = 0;
  11271. // let's count var_decl first, we seem to waste a lot of
  11272. // space if we hoist `var` when there's only one.
  11273. self.walk(new TreeWalker(function(node){
  11274. if (node instanceof AST_Scope && node !== self)
  11275. return true;
  11276. if (node instanceof AST_Var) {
  11277. ++var_decl;
  11278. return true;
  11279. }
  11280. }));
  11281. hoist_vars = hoist_vars && var_decl > 1;
  11282. var tt = new TreeTransformer(
  11283. function before(node) {
  11284. if (node !== self) {
  11285. if (node instanceof AST_Directive) {
  11286. dirs.push(node);
  11287. return make_node(AST_EmptyStatement, node);
  11288. }
  11289. if (node instanceof AST_Defun && hoist_funs) {
  11290. hoisted.push(node);
  11291. return make_node(AST_EmptyStatement, node);
  11292. }
  11293. if (node instanceof AST_Var && hoist_vars) {
  11294. node.definitions.forEach(function(def){
  11295. vars.set(def.name.name, def);
  11296. ++vars_found;
  11297. });
  11298. var seq = node.to_assignments();
  11299. var p = tt.parent();
  11300. if (p instanceof AST_ForIn && p.init === node) {
  11301. if (seq == null) return node.definitions[0].name;
  11302. return seq;
  11303. }
  11304. if (p instanceof AST_For && p.init === node) {
  11305. return seq;
  11306. }
  11307. if (!seq) return make_node(AST_EmptyStatement, node);
  11308. return make_node(AST_SimpleStatement, node, {
  11309. body: seq
  11310. });
  11311. }
  11312. if (node instanceof AST_Scope)
  11313. return node; // to avoid descending in nested scopes
  11314. }
  11315. }
  11316. );
  11317. self = self.transform(tt);
  11318. if (vars_found > 0) {
  11319. // collect only vars which don't show up in self's arguments list
  11320. var defs = [];
  11321. vars.each(function(def, name){
  11322. if (self instanceof AST_Lambda
  11323. && find_if(function(x){ return x.name == def.name.name },
  11324. self.argnames)) {
  11325. vars.del(name);
  11326. } else {
  11327. def = def.clone();
  11328. def.value = null;
  11329. defs.push(def);
  11330. vars.set(name, def);
  11331. }
  11332. });
  11333. if (defs.length > 0) {
  11334. // try to merge in assignments
  11335. for (var i = 0; i < self.body.length;) {
  11336. if (self.body[i] instanceof AST_SimpleStatement) {
  11337. var expr = self.body[i].body, sym, assign;
  11338. if (expr instanceof AST_Assign
  11339. && expr.operator == "="
  11340. && (sym = expr.left) instanceof AST_Symbol
  11341. && vars.has(sym.name))
  11342. {
  11343. var def = vars.get(sym.name);
  11344. if (def.value) break;
  11345. def.value = expr.right;
  11346. remove(defs, def);
  11347. defs.push(def);
  11348. self.body.splice(i, 1);
  11349. continue;
  11350. }
  11351. if (expr instanceof AST_Seq
  11352. && (assign = expr.car) instanceof AST_Assign
  11353. && assign.operator == "="
  11354. && (sym = assign.left) instanceof AST_Symbol
  11355. && vars.has(sym.name))
  11356. {
  11357. var def = vars.get(sym.name);
  11358. if (def.value) break;
  11359. def.value = assign.right;
  11360. remove(defs, def);
  11361. defs.push(def);
  11362. self.body[i].body = expr.cdr;
  11363. continue;
  11364. }
  11365. }
  11366. if (self.body[i] instanceof AST_EmptyStatement) {
  11367. self.body.splice(i, 1);
  11368. continue;
  11369. }
  11370. if (self.body[i] instanceof AST_BlockStatement) {
  11371. var tmp = [ i, 1 ].concat(self.body[i].body);
  11372. self.body.splice.apply(self.body, tmp);
  11373. continue;
  11374. }
  11375. break;
  11376. }
  11377. defs = make_node(AST_Var, self, {
  11378. definitions: defs
  11379. });
  11380. hoisted.push(defs);
  11381. };
  11382. }
  11383. self.body = dirs.concat(hoisted, self.body);
  11384. }
  11385. return self;
  11386. });
  11387. OPT(AST_SimpleStatement, function(self, compressor){
  11388. if (compressor.option("side_effects")) {
  11389. if (!self.body.has_side_effects(compressor)) {
  11390. compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
  11391. return make_node(AST_EmptyStatement, self);
  11392. }
  11393. }
  11394. return self;
  11395. });
  11396. OPT(AST_DWLoop, function(self, compressor){
  11397. var cond = self.condition.evaluate(compressor);
  11398. self.condition = cond[0];
  11399. if (!compressor.option("loops")) return self;
  11400. if (cond.length > 1) {
  11401. if (cond[1]) {
  11402. return make_node(AST_For, self, {
  11403. body: self.body
  11404. });
  11405. } else if (self instanceof AST_While) {
  11406. if (compressor.option("dead_code")) {
  11407. var a = [];
  11408. extract_declarations_from_unreachable_code(compressor, self.body, a);
  11409. return make_node(AST_BlockStatement, self, { body: a });
  11410. }
  11411. }
  11412. }
  11413. return self;
  11414. });
  11415. function if_break_in_loop(self, compressor) {
  11416. function drop_it(rest) {
  11417. rest = as_statement_array(rest);
  11418. if (self.body instanceof AST_BlockStatement) {
  11419. self.body = self.body.clone();
  11420. self.body.body = rest.concat(self.body.body.slice(1));
  11421. self.body = self.body.transform(compressor);
  11422. } else {
  11423. self.body = make_node(AST_BlockStatement, self.body, {
  11424. body: rest
  11425. }).transform(compressor);
  11426. }
  11427. if_break_in_loop(self, compressor);
  11428. }
  11429. var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
  11430. if (first instanceof AST_If) {
  11431. if (first.body instanceof AST_Break
  11432. && compressor.loopcontrol_target(first.body.label) === self) {
  11433. if (self.condition) {
  11434. self.condition = make_node(AST_Binary, self.condition, {
  11435. left: self.condition,
  11436. operator: "&&",
  11437. right: first.condition.negate(compressor),
  11438. });
  11439. } else {
  11440. self.condition = first.condition.negate(compressor);
  11441. }
  11442. drop_it(first.alternative);
  11443. }
  11444. else if (first.alternative instanceof AST_Break
  11445. && compressor.loopcontrol_target(first.alternative.label) === self) {
  11446. if (self.condition) {
  11447. self.condition = make_node(AST_Binary, self.condition, {
  11448. left: self.condition,
  11449. operator: "&&",
  11450. right: first.condition,
  11451. });
  11452. } else {
  11453. self.condition = first.condition;
  11454. }
  11455. drop_it(first.body);
  11456. }
  11457. }
  11458. };
  11459. OPT(AST_While, function(self, compressor) {
  11460. if (!compressor.option("loops")) return self;
  11461. self = AST_DWLoop.prototype.optimize.call(self, compressor);
  11462. if (self instanceof AST_While) {
  11463. if_break_in_loop(self, compressor);
  11464. self = make_node(AST_For, self, self).transform(compressor);
  11465. }
  11466. return self;
  11467. });
  11468. OPT(AST_For, function(self, compressor){
  11469. var cond = self.condition;
  11470. if (cond) {
  11471. cond = cond.evaluate(compressor);
  11472. self.condition = cond[0];
  11473. }
  11474. if (!compressor.option("loops")) return self;
  11475. if (cond) {
  11476. if (cond.length > 1 && !cond[1]) {
  11477. if (compressor.option("dead_code")) {
  11478. var a = [];
  11479. if (self.init instanceof AST_Statement) {
  11480. a.push(self.init);
  11481. }
  11482. else if (self.init) {
  11483. a.push(make_node(AST_SimpleStatement, self.init, {
  11484. body: self.init
  11485. }));
  11486. }
  11487. extract_declarations_from_unreachable_code(compressor, self.body, a);
  11488. return make_node(AST_BlockStatement, self, { body: a });
  11489. }
  11490. }
  11491. }
  11492. if_break_in_loop(self, compressor);
  11493. return self;
  11494. });
  11495. OPT(AST_If, function(self, compressor){
  11496. if (!compressor.option("conditionals")) return self;
  11497. // if condition can be statically determined, warn and drop
  11498. // one of the blocks. note, statically determined implies
  11499. // “has no side effects”; also it doesn't work for cases like
  11500. // `x && true`, though it probably should.
  11501. var cond = self.condition.evaluate(compressor);
  11502. self.condition = cond[0];
  11503. if (cond.length > 1) {
  11504. if (cond[1]) {
  11505. compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
  11506. if (compressor.option("dead_code")) {
  11507. var a = [];
  11508. if (self.alternative) {
  11509. extract_declarations_from_unreachable_code(compressor, self.alternative, a);
  11510. }
  11511. a.push(self.body);
  11512. return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
  11513. }
  11514. } else {
  11515. compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
  11516. if (compressor.option("dead_code")) {
  11517. var a = [];
  11518. extract_declarations_from_unreachable_code(compressor, self.body, a);
  11519. if (self.alternative) a.push(self.alternative);
  11520. return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
  11521. }
  11522. }
  11523. }
  11524. if (is_empty(self.alternative)) self.alternative = null;
  11525. var negated = self.condition.negate(compressor);
  11526. var negated_is_best = best_of(self.condition, negated) === negated;
  11527. if (self.alternative && negated_is_best) {
  11528. negated_is_best = false; // because we already do the switch here.
  11529. self.condition = negated;
  11530. var tmp = self.body;
  11531. self.body = self.alternative || make_node(AST_EmptyStatement);
  11532. self.alternative = tmp;
  11533. }
  11534. if (is_empty(self.body) && is_empty(self.alternative)) {
  11535. return make_node(AST_SimpleStatement, self.condition, {
  11536. body: self.condition
  11537. }).transform(compressor);
  11538. }
  11539. if (self.body instanceof AST_SimpleStatement
  11540. && self.alternative instanceof AST_SimpleStatement) {
  11541. return make_node(AST_SimpleStatement, self, {
  11542. body: make_node(AST_Conditional, self, {
  11543. condition : self.condition,
  11544. consequent : self.body.body,
  11545. alternative : self.alternative.body
  11546. })
  11547. }).transform(compressor);
  11548. }
  11549. if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
  11550. if (negated_is_best) return make_node(AST_SimpleStatement, self, {
  11551. body: make_node(AST_Binary, self, {
  11552. operator : "||",
  11553. left : negated,
  11554. right : self.body.body
  11555. })
  11556. }).transform(compressor);
  11557. return make_node(AST_SimpleStatement, self, {
  11558. body: make_node(AST_Binary, self, {
  11559. operator : "&&",
  11560. left : self.condition,
  11561. right : self.body.body
  11562. })
  11563. }).transform(compressor);
  11564. }
  11565. if (self.body instanceof AST_EmptyStatement
  11566. && self.alternative
  11567. && self.alternative instanceof AST_SimpleStatement) {
  11568. return make_node(AST_SimpleStatement, self, {
  11569. body: make_node(AST_Binary, self, {
  11570. operator : "||",
  11571. left : self.condition,
  11572. right : self.alternative.body
  11573. })
  11574. }).transform(compressor);
  11575. }
  11576. if (self.body instanceof AST_Exit
  11577. && self.alternative instanceof AST_Exit
  11578. && self.body.TYPE == self.alternative.TYPE) {
  11579. return make_node(self.body.CTOR, self, {
  11580. value: make_node(AST_Conditional, self, {
  11581. condition : self.condition,
  11582. consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
  11583. alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
  11584. })
  11585. }).transform(compressor);
  11586. }
  11587. if (self.body instanceof AST_If
  11588. && !self.body.alternative
  11589. && !self.alternative) {
  11590. self.condition = make_node(AST_Binary, self.condition, {
  11591. operator: "&&",
  11592. left: self.condition,
  11593. right: self.body.condition
  11594. }).transform(compressor);
  11595. self.body = self.body.body;
  11596. }
  11597. if (aborts(self.body)) {
  11598. if (self.alternative) {
  11599. var alt = self.alternative;
  11600. self.alternative = null;
  11601. return make_node(AST_BlockStatement, self, {
  11602. body: [ self, alt ]
  11603. }).transform(compressor);
  11604. }
  11605. }
  11606. if (aborts(self.alternative)) {
  11607. var body = self.body;
  11608. self.body = self.alternative;
  11609. self.condition = negated_is_best ? negated : self.condition.negate(compressor);
  11610. self.alternative = null;
  11611. return make_node(AST_BlockStatement, self, {
  11612. body: [ self, body ]
  11613. }).transform(compressor);
  11614. }
  11615. return self;
  11616. });
  11617. OPT(AST_Switch, function(self, compressor){
  11618. if (self.body.length == 0 && compressor.option("conditionals")) {
  11619. return make_node(AST_SimpleStatement, self, {
  11620. body: self.expression
  11621. }).transform(compressor);
  11622. }
  11623. for(;;) {
  11624. var last_branch = self.body[self.body.length - 1];
  11625. if (last_branch) {
  11626. var stat = last_branch.body[last_branch.body.length - 1]; // last statement
  11627. if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
  11628. last_branch.body.pop();
  11629. if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
  11630. self.body.pop();
  11631. continue;
  11632. }
  11633. }
  11634. break;
  11635. }
  11636. var exp = self.expression.evaluate(compressor);
  11637. out: if (exp.length == 2) try {
  11638. // constant expression
  11639. self.expression = exp[0];
  11640. if (!compressor.option("dead_code")) break out;
  11641. var value = exp[1];
  11642. var in_if = false;
  11643. var in_block = false;
  11644. var started = false;
  11645. var stopped = false;
  11646. var ruined = false;
  11647. var tt = new TreeTransformer(function(node, descend, in_list){
  11648. if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
  11649. // no need to descend these node types
  11650. return node;
  11651. }
  11652. else if (node instanceof AST_Switch && node === self) {
  11653. node = node.clone();
  11654. descend(node, this);
  11655. return ruined ? node : make_node(AST_BlockStatement, node, {
  11656. body: node.body.reduce(function(a, branch){
  11657. return a.concat(branch.body);
  11658. }, [])
  11659. }).transform(compressor);
  11660. }
  11661. else if (node instanceof AST_If || node instanceof AST_Try) {
  11662. var save = in_if;
  11663. in_if = !in_block;
  11664. descend(node, this);
  11665. in_if = save;
  11666. return node;
  11667. }
  11668. else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
  11669. var save = in_block;
  11670. in_block = true;
  11671. descend(node, this);
  11672. in_block = save;
  11673. return node;
  11674. }
  11675. else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
  11676. if (in_if) {
  11677. ruined = true;
  11678. return node;
  11679. }
  11680. if (in_block) return node;
  11681. stopped = true;
  11682. return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
  11683. }
  11684. else if (node instanceof AST_SwitchBranch && this.parent() === self) {
  11685. if (stopped) return MAP.skip;
  11686. if (node instanceof AST_Case) {
  11687. var exp = node.expression.evaluate(compressor);
  11688. if (exp.length < 2) {
  11689. // got a case with non-constant expression, baling out
  11690. throw self;
  11691. }
  11692. if (exp[1] === value || started) {
  11693. started = true;
  11694. if (aborts(node)) stopped = true;
  11695. descend(node, this);
  11696. return node;
  11697. }
  11698. return MAP.skip;
  11699. }
  11700. descend(node, this);
  11701. return node;
  11702. }
  11703. });
  11704. tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
  11705. self = self.transform(tt);
  11706. } catch(ex) {
  11707. if (ex !== self) throw ex;
  11708. }
  11709. return self;
  11710. });
  11711. OPT(AST_Case, function(self, compressor){
  11712. self.body = tighten_body(self.body, compressor);
  11713. return self;
  11714. });
  11715. OPT(AST_Try, function(self, compressor){
  11716. self.body = tighten_body(self.body, compressor);
  11717. return self;
  11718. });
  11719. AST_Definitions.DEFMETHOD("remove_initializers", function(){
  11720. this.definitions.forEach(function(def){ def.value = null });
  11721. });
  11722. AST_Definitions.DEFMETHOD("to_assignments", function(){
  11723. var assignments = this.definitions.reduce(function(a, def){
  11724. if (def.value) {
  11725. var name = make_node(AST_SymbolRef, def.name, def.name);
  11726. a.push(make_node(AST_Assign, def, {
  11727. operator : "=",
  11728. left : name,
  11729. right : def.value
  11730. }));
  11731. }
  11732. return a;
  11733. }, []);
  11734. if (assignments.length == 0) return null;
  11735. return AST_Seq.from_array(assignments);
  11736. });
  11737. OPT(AST_Definitions, function(self, compressor){
  11738. if (self.definitions.length == 0)
  11739. return make_node(AST_EmptyStatement, self);
  11740. return self;
  11741. });
  11742. OPT(AST_Function, function(self, compressor){
  11743. self = AST_Lambda.prototype.optimize.call(self, compressor);
  11744. if (compressor.option("unused")) {
  11745. if (self.name && self.name.unreferenced()) {
  11746. self.name = null;
  11747. }
  11748. }
  11749. return self;
  11750. });
  11751. OPT(AST_Call, function(self, compressor){
  11752. if (compressor.option("unsafe")) {
  11753. var exp = self.expression;
  11754. if (exp instanceof AST_SymbolRef && exp.undeclared()) {
  11755. switch (exp.name) {
  11756. case "Array":
  11757. if (self.args.length != 1) {
  11758. return make_node(AST_Array, self, {
  11759. elements: self.args
  11760. }).transform(compressor);
  11761. }
  11762. break;
  11763. case "Object":
  11764. if (self.args.length == 0) {
  11765. return make_node(AST_Object, self, {
  11766. properties: []
  11767. });
  11768. }
  11769. break;
  11770. case "String":
  11771. if (self.args.length == 0) return make_node(AST_String, self, {
  11772. value: ""
  11773. });
  11774. if (self.args.length <= 1) return make_node(AST_Binary, self, {
  11775. left: self.args[0],
  11776. operator: "+",
  11777. right: make_node(AST_String, self, { value: "" })
  11778. }).transform(compressor);
  11779. break;
  11780. case "Number":
  11781. if (self.args.length == 0) return make_node(AST_Number, self, {
  11782. value: 0
  11783. });
  11784. if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
  11785. expression: self.args[0],
  11786. operator: "+"
  11787. }).transform(compressor);
  11788. case "Boolean":
  11789. if (self.args.length == 0) return make_node(AST_False, self);
  11790. if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
  11791. expression: make_node(AST_UnaryPrefix, null, {
  11792. expression: self.args[0],
  11793. operator: "!"
  11794. }),
  11795. operator: "!"
  11796. }).transform(compressor);
  11797. break;
  11798. case "Function":
  11799. if (all(self.args, function(x){ return x instanceof AST_String })) {
  11800. // quite a corner-case, but we can handle it:
  11801. // https://github.com/mishoo/UglifyJS2/issues/203
  11802. // if the code argument is a constant, then we can minify it.
  11803. try {
  11804. var code = "(function(" + self.args.slice(0, -1).map(function(arg){
  11805. return arg.value;
  11806. }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
  11807. var ast = parse(code);
  11808. ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
  11809. var comp = new Compressor(compressor.options);
  11810. ast = ast.transform(comp);
  11811. ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
  11812. ast.mangle_names();
  11813. var fun;
  11814. try {
  11815. ast.walk(new TreeWalker(function(node){
  11816. if (node instanceof AST_Lambda) {
  11817. fun = node;
  11818. throw ast;
  11819. }
  11820. }));
  11821. } catch(ex) {
  11822. if (ex !== ast) throw ex;
  11823. };
  11824. var args = fun.argnames.map(function(arg, i){
  11825. return make_node(AST_String, self.args[i], {
  11826. value: arg.print_to_string()
  11827. });
  11828. });
  11829. var code = OutputStream();
  11830. AST_BlockStatement.prototype._codegen.call(fun, fun, code);
  11831. code = code.toString().replace(/^\{|\}$/g, "");
  11832. args.push(make_node(AST_String, self.args[self.args.length - 1], {
  11833. value: code
  11834. }));
  11835. self.args = args;
  11836. return self;
  11837. } catch(ex) {
  11838. if (ex instanceof JS_Parse_Error) {
  11839. compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
  11840. compressor.warn(ex.toString());
  11841. } else {
  11842. console.log(ex);
  11843. throw ex;
  11844. }
  11845. }
  11846. }
  11847. break;
  11848. }
  11849. }
  11850. else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
  11851. return make_node(AST_Binary, self, {
  11852. left: make_node(AST_String, self, { value: "" }),
  11853. operator: "+",
  11854. right: exp.expression
  11855. }).transform(compressor);
  11856. }
  11857. else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
  11858. var separator = self.args.length == 0 ? "," : self.args[0].evaluate(compressor)[1];
  11859. if (separator == null) break EXIT; // not a constant
  11860. var elements = exp.expression.elements.reduce(function(a, el){
  11861. el = el.evaluate(compressor);
  11862. if (a.length == 0 || el.length == 1) {
  11863. a.push(el);
  11864. } else {
  11865. var last = a[a.length - 1];
  11866. if (last.length == 2) {
  11867. // it's a constant
  11868. var val = "" + last[1] + separator + el[1];
  11869. a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ];
  11870. } else {
  11871. a.push(el);
  11872. }
  11873. }
  11874. return a;
  11875. }, []);
  11876. if (elements.length == 0) return make_node(AST_String, self, { value: "" });
  11877. if (elements.length == 1) return elements[0][0];
  11878. if (separator == "") {
  11879. var first;
  11880. if (elements[0][0] instanceof AST_String
  11881. || elements[1][0] instanceof AST_String) {
  11882. first = elements.shift()[0];
  11883. } else {
  11884. first = make_node(AST_String, self, { value: "" });
  11885. }
  11886. return elements.reduce(function(prev, el){
  11887. return make_node(AST_Binary, el[0], {
  11888. operator : "+",
  11889. left : prev,
  11890. right : el[0],
  11891. });
  11892. }, first).transform(compressor);
  11893. }
  11894. // need this awkward cloning to not affect original element
  11895. // best_of will decide which one to get through.
  11896. var node = self.clone();
  11897. node.expression = node.expression.clone();
  11898. node.expression.expression = node.expression.expression.clone();
  11899. node.expression.expression.elements = elements.map(function(el){
  11900. return el[0];
  11901. });
  11902. return best_of(self, node);
  11903. }
  11904. }
  11905. if (compressor.option("side_effects")) {
  11906. if (self.expression instanceof AST_Function
  11907. && self.args.length == 0
  11908. && !AST_Block.prototype.has_side_effects.call(self.expression, compressor)) {
  11909. return make_node(AST_Undefined, self).transform(compressor);
  11910. }
  11911. }
  11912. if (compressor.option("drop_console")) {
  11913. if (self.expression instanceof AST_PropAccess &&
  11914. self.expression.expression instanceof AST_SymbolRef &&
  11915. self.expression.expression.name == "console" &&
  11916. self.expression.expression.undeclared()) {
  11917. return make_node(AST_Undefined, self).transform(compressor);
  11918. }
  11919. }
  11920. return self.evaluate(compressor)[0];
  11921. });
  11922. OPT(AST_New, function(self, compressor){
  11923. if (compressor.option("unsafe")) {
  11924. var exp = self.expression;
  11925. if (exp instanceof AST_SymbolRef && exp.undeclared()) {
  11926. switch (exp.name) {
  11927. case "Object":
  11928. case "RegExp":
  11929. case "Function":
  11930. case "Error":
  11931. case "Array":
  11932. return make_node(AST_Call, self, self).transform(compressor);
  11933. }
  11934. }
  11935. }
  11936. return self;
  11937. });
  11938. OPT(AST_Seq, function(self, compressor){
  11939. if (!compressor.option("side_effects"))
  11940. return self;
  11941. if (!self.car.has_side_effects(compressor)) {
  11942. // we shouldn't compress (1,eval)(something) to
  11943. // eval(something) because that changes the meaning of
  11944. // eval (becomes lexical instead of global).
  11945. var p;
  11946. if (!(self.cdr instanceof AST_SymbolRef
  11947. && self.cdr.name == "eval"
  11948. && self.cdr.undeclared()
  11949. && (p = compressor.parent()) instanceof AST_Call
  11950. && p.expression === self)) {
  11951. return self.cdr;
  11952. }
  11953. }
  11954. if (compressor.option("cascade")) {
  11955. if (self.car instanceof AST_Assign
  11956. && !self.car.left.has_side_effects(compressor)) {
  11957. if (self.car.left.equivalent_to(self.cdr)) {
  11958. return self.car;
  11959. }
  11960. if (self.cdr instanceof AST_Call
  11961. && self.cdr.expression.equivalent_to(self.car.left)) {
  11962. self.cdr.expression = self.car;
  11963. return self.cdr;
  11964. }
  11965. }
  11966. if (!self.car.has_side_effects(compressor)
  11967. && !self.cdr.has_side_effects(compressor)
  11968. && self.car.equivalent_to(self.cdr)) {
  11969. return self.car;
  11970. }
  11971. }
  11972. return self;
  11973. });
  11974. AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
  11975. if (compressor.option("sequences")) {
  11976. if (this.expression instanceof AST_Seq) {
  11977. var seq = this.expression;
  11978. var x = seq.to_array();
  11979. this.expression = x.pop();
  11980. x.push(this);
  11981. seq = AST_Seq.from_array(x).transform(compressor);
  11982. return seq;
  11983. }
  11984. }
  11985. return this;
  11986. });
  11987. OPT(AST_UnaryPostfix, function(self, compressor){
  11988. return self.lift_sequences(compressor);
  11989. });
  11990. OPT(AST_UnaryPrefix, function(self, compressor){
  11991. self = self.lift_sequences(compressor);
  11992. var e = self.expression;
  11993. if (compressor.option("booleans") && compressor.in_boolean_context()) {
  11994. switch (self.operator) {
  11995. case "!":
  11996. if (e instanceof AST_UnaryPrefix && e.operator == "!") {
  11997. // !!foo ==> foo, if we're in boolean context
  11998. return e.expression;
  11999. }
  12000. break;
  12001. case "typeof":
  12002. // typeof always returns a non-empty string, thus it's
  12003. // always true in booleans
  12004. compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
  12005. return make_node(AST_True, self);
  12006. }
  12007. if (e instanceof AST_Binary && self.operator == "!") {
  12008. self = best_of(self, e.negate(compressor));
  12009. }
  12010. }
  12011. return self.evaluate(compressor)[0];
  12012. });
  12013. function has_side_effects_or_prop_access(node, compressor) {
  12014. var save_pure_getters = compressor.option("pure_getters");
  12015. compressor.options.pure_getters = false;
  12016. var ret = node.has_side_effects(compressor);
  12017. compressor.options.pure_getters = save_pure_getters;
  12018. return ret;
  12019. }
  12020. AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
  12021. if (compressor.option("sequences")) {
  12022. if (this.left instanceof AST_Seq) {
  12023. var seq = this.left;
  12024. var x = seq.to_array();
  12025. this.left = x.pop();
  12026. x.push(this);
  12027. seq = AST_Seq.from_array(x).transform(compressor);
  12028. return seq;
  12029. }
  12030. if (this.right instanceof AST_Seq
  12031. && this instanceof AST_Assign
  12032. && !has_side_effects_or_prop_access(this.left, compressor)) {
  12033. var seq = this.right;
  12034. var x = seq.to_array();
  12035. this.right = x.pop();
  12036. x.push(this);
  12037. seq = AST_Seq.from_array(x).transform(compressor);
  12038. return seq;
  12039. }
  12040. }
  12041. return this;
  12042. });
  12043. var commutativeOperators = makePredicate("== === != !== * & | ^");
  12044. OPT(AST_Binary, function(self, compressor){
  12045. var reverse = compressor.has_directive("use asm") ? noop
  12046. : function(op, force) {
  12047. if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
  12048. if (op) self.operator = op;
  12049. var tmp = self.left;
  12050. self.left = self.right;
  12051. self.right = tmp;
  12052. }
  12053. };
  12054. if (commutativeOperators(self.operator)) {
  12055. if (self.right instanceof AST_Constant
  12056. && !(self.left instanceof AST_Constant)) {
  12057. // if right is a constant, whatever side effects the
  12058. // left side might have could not influence the
  12059. // result. hence, force switch.
  12060. if (!(self.left instanceof AST_Binary
  12061. && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
  12062. reverse(null, true);
  12063. }
  12064. }
  12065. if (/^[!=]==?$/.test(self.operator)) {
  12066. if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) {
  12067. if (self.right.consequent instanceof AST_SymbolRef
  12068. && self.right.consequent.definition() === self.left.definition()) {
  12069. if (/^==/.test(self.operator)) return self.right.condition;
  12070. if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor);
  12071. }
  12072. if (self.right.alternative instanceof AST_SymbolRef
  12073. && self.right.alternative.definition() === self.left.definition()) {
  12074. if (/^==/.test(self.operator)) return self.right.condition.negate(compressor);
  12075. if (/^!=/.test(self.operator)) return self.right.condition;
  12076. }
  12077. }
  12078. if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) {
  12079. if (self.left.consequent instanceof AST_SymbolRef
  12080. && self.left.consequent.definition() === self.right.definition()) {
  12081. if (/^==/.test(self.operator)) return self.left.condition;
  12082. if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor);
  12083. }
  12084. if (self.left.alternative instanceof AST_SymbolRef
  12085. && self.left.alternative.definition() === self.right.definition()) {
  12086. if (/^==/.test(self.operator)) return self.left.condition.negate(compressor);
  12087. if (/^!=/.test(self.operator)) return self.left.condition;
  12088. }
  12089. }
  12090. }
  12091. }
  12092. self = self.lift_sequences(compressor);
  12093. if (compressor.option("comparisons")) switch (self.operator) {
  12094. case "===":
  12095. case "!==":
  12096. if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
  12097. (self.left.is_boolean() && self.right.is_boolean())) {
  12098. self.operator = self.operator.substr(0, 2);
  12099. }
  12100. // XXX: intentionally falling down to the next case
  12101. case "==":
  12102. case "!=":
  12103. if (self.left instanceof AST_String
  12104. && self.left.value == "undefined"
  12105. && self.right instanceof AST_UnaryPrefix
  12106. && self.right.operator == "typeof"
  12107. && compressor.option("unsafe")) {
  12108. if (!(self.right.expression instanceof AST_SymbolRef)
  12109. || !self.right.expression.undeclared()) {
  12110. self.right = self.right.expression;
  12111. self.left = make_node(AST_Undefined, self.left).optimize(compressor);
  12112. if (self.operator.length == 2) self.operator += "=";
  12113. }
  12114. }
  12115. break;
  12116. }
  12117. if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
  12118. case "&&":
  12119. var ll = self.left.evaluate(compressor);
  12120. var rr = self.right.evaluate(compressor);
  12121. if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
  12122. compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
  12123. return make_node(AST_False, self);
  12124. }
  12125. if (ll.length > 1 && ll[1]) {
  12126. return rr[0];
  12127. }
  12128. if (rr.length > 1 && rr[1]) {
  12129. return ll[0];
  12130. }
  12131. break;
  12132. case "||":
  12133. var ll = self.left.evaluate(compressor);
  12134. var rr = self.right.evaluate(compressor);
  12135. if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
  12136. compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
  12137. return make_node(AST_True, self);
  12138. }
  12139. if (ll.length > 1 && !ll[1]) {
  12140. return rr[0];
  12141. }
  12142. if (rr.length > 1 && !rr[1]) {
  12143. return ll[0];
  12144. }
  12145. break;
  12146. case "+":
  12147. var ll = self.left.evaluate(compressor);
  12148. var rr = self.right.evaluate(compressor);
  12149. if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
  12150. (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
  12151. compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
  12152. return make_node(AST_True, self);
  12153. }
  12154. break;
  12155. }
  12156. if (compressor.option("comparisons")) {
  12157. if (!(compressor.parent() instanceof AST_Binary)
  12158. || compressor.parent() instanceof AST_Assign) {
  12159. var negated = make_node(AST_UnaryPrefix, self, {
  12160. operator: "!",
  12161. expression: self.negate(compressor)
  12162. });
  12163. self = best_of(self, negated);
  12164. }
  12165. switch (self.operator) {
  12166. case "<": reverse(">"); break;
  12167. case "<=": reverse(">="); break;
  12168. }
  12169. }
  12170. if (self.operator == "+" && self.right instanceof AST_String
  12171. && self.right.getValue() === "" && self.left instanceof AST_Binary
  12172. && self.left.operator == "+" && self.left.is_string(compressor)) {
  12173. return self.left;
  12174. }
  12175. if (compressor.option("evaluate")) {
  12176. if (self.operator == "+") {
  12177. if (self.left instanceof AST_Constant
  12178. && self.right instanceof AST_Binary
  12179. && self.right.operator == "+"
  12180. && self.right.left instanceof AST_Constant
  12181. && self.right.is_string(compressor)) {
  12182. self = make_node(AST_Binary, self, {
  12183. operator: "+",
  12184. left: make_node(AST_String, null, {
  12185. value: "" + self.left.getValue() + self.right.left.getValue(),
  12186. start: self.left.start,
  12187. end: self.right.left.end
  12188. }),
  12189. right: self.right.right
  12190. });
  12191. }
  12192. if (self.right instanceof AST_Constant
  12193. && self.left instanceof AST_Binary
  12194. && self.left.operator == "+"
  12195. && self.left.right instanceof AST_Constant
  12196. && self.left.is_string(compressor)) {
  12197. self = make_node(AST_Binary, self, {
  12198. operator: "+",
  12199. left: self.left.left,
  12200. right: make_node(AST_String, null, {
  12201. value: "" + self.left.right.getValue() + self.right.getValue(),
  12202. start: self.left.right.start,
  12203. end: self.right.end
  12204. })
  12205. });
  12206. }
  12207. if (self.left instanceof AST_Binary
  12208. && self.left.operator == "+"
  12209. && self.left.is_string(compressor)
  12210. && self.left.right instanceof AST_Constant
  12211. && self.right instanceof AST_Binary
  12212. && self.right.operator == "+"
  12213. && self.right.left instanceof AST_Constant
  12214. && self.right.is_string(compressor)) {
  12215. self = make_node(AST_Binary, self, {
  12216. operator: "+",
  12217. left: make_node(AST_Binary, self.left, {
  12218. operator: "+",
  12219. left: self.left.left,
  12220. right: make_node(AST_String, null, {
  12221. value: "" + self.left.right.getValue() + self.right.left.getValue(),
  12222. start: self.left.right.start,
  12223. end: self.right.left.end
  12224. })
  12225. }),
  12226. right: self.right.right
  12227. });
  12228. }
  12229. }
  12230. }
  12231. // x * (y * z) ==> x * y * z
  12232. if (self.right instanceof AST_Binary
  12233. && self.right.operator == self.operator
  12234. && (self.operator == "*" || self.operator == "&&" || self.operator == "||"))
  12235. {
  12236. self.left = make_node(AST_Binary, self.left, {
  12237. operator : self.operator,
  12238. left : self.left,
  12239. right : self.right.left
  12240. });
  12241. self.right = self.right.right;
  12242. return self.transform(compressor);
  12243. }
  12244. return self.evaluate(compressor)[0];
  12245. });
  12246. OPT(AST_SymbolRef, function(self, compressor){
  12247. if (self.undeclared()) {
  12248. var defines = compressor.option("global_defs");
  12249. if (defines && defines.hasOwnProperty(self.name)) {
  12250. return make_node_from_constant(compressor, defines[self.name], self);
  12251. }
  12252. switch (self.name) {
  12253. case "undefined":
  12254. return make_node(AST_Undefined, self);
  12255. case "NaN":
  12256. return make_node(AST_NaN, self);
  12257. case "Infinity":
  12258. return make_node(AST_Infinity, self);
  12259. }
  12260. }
  12261. return self;
  12262. });
  12263. OPT(AST_Undefined, function(self, compressor){
  12264. if (compressor.option("unsafe")) {
  12265. var scope = compressor.find_parent(AST_Scope);
  12266. var undef = scope.find_variable("undefined");
  12267. if (undef) {
  12268. var ref = make_node(AST_SymbolRef, self, {
  12269. name : "undefined",
  12270. scope : scope,
  12271. thedef : undef
  12272. });
  12273. ref.reference();
  12274. return ref;
  12275. }
  12276. }
  12277. return self;
  12278. });
  12279. var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
  12280. OPT(AST_Assign, function(self, compressor){
  12281. self = self.lift_sequences(compressor);
  12282. if (self.operator == "="
  12283. && self.left instanceof AST_SymbolRef
  12284. && self.right instanceof AST_Binary
  12285. && self.right.left instanceof AST_SymbolRef
  12286. && self.right.left.name == self.left.name
  12287. && member(self.right.operator, ASSIGN_OPS)) {
  12288. self.operator = self.right.operator + "=";
  12289. self.right = self.right.right;
  12290. }
  12291. return self;
  12292. });
  12293. OPT(AST_Conditional, function(self, compressor){
  12294. if (!compressor.option("conditionals")) return self;
  12295. if (self.condition instanceof AST_Seq) {
  12296. var car = self.condition.car;
  12297. self.condition = self.condition.cdr;
  12298. return AST_Seq.cons(car, self);
  12299. }
  12300. var cond = self.condition.evaluate(compressor);
  12301. if (cond.length > 1) {
  12302. if (cond[1]) {
  12303. compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
  12304. return self.consequent;
  12305. } else {
  12306. compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
  12307. return self.alternative;
  12308. }
  12309. }
  12310. var negated = cond[0].negate(compressor);
  12311. if (best_of(cond[0], negated) === negated) {
  12312. self = make_node(AST_Conditional, self, {
  12313. condition: negated,
  12314. consequent: self.alternative,
  12315. alternative: self.consequent
  12316. });
  12317. }
  12318. var consequent = self.consequent;
  12319. var alternative = self.alternative;
  12320. if (consequent instanceof AST_Assign
  12321. && alternative instanceof AST_Assign
  12322. && consequent.operator == alternative.operator
  12323. && consequent.left.equivalent_to(alternative.left)
  12324. ) {
  12325. /*
  12326. * Stuff like this:
  12327. * if (foo) exp = something; else exp = something_else;
  12328. * ==>
  12329. * exp = foo ? something : something_else;
  12330. */
  12331. self = make_node(AST_Assign, self, {
  12332. operator: consequent.operator,
  12333. left: consequent.left,
  12334. right: make_node(AST_Conditional, self, {
  12335. condition: self.condition,
  12336. consequent: consequent.right,
  12337. alternative: alternative.right
  12338. })
  12339. });
  12340. }
  12341. return self;
  12342. });
  12343. OPT(AST_Boolean, function(self, compressor){
  12344. if (compressor.option("booleans")) {
  12345. var p = compressor.parent();
  12346. if (p instanceof AST_Binary && (p.operator == "=="
  12347. || p.operator == "!=")) {
  12348. compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
  12349. operator : p.operator,
  12350. value : self.value,
  12351. file : p.start.file,
  12352. line : p.start.line,
  12353. col : p.start.col,
  12354. });
  12355. return make_node(AST_Number, self, {
  12356. value: +self.value
  12357. });
  12358. }
  12359. return make_node(AST_UnaryPrefix, self, {
  12360. operator: "!",
  12361. expression: make_node(AST_Number, self, {
  12362. value: 1 - self.value
  12363. })
  12364. });
  12365. }
  12366. return self;
  12367. });
  12368. OPT(AST_Sub, function(self, compressor){
  12369. var prop = self.property;
  12370. if (prop instanceof AST_String && compressor.option("properties")) {
  12371. prop = prop.getValue();
  12372. if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) {
  12373. return make_node(AST_Dot, self, {
  12374. expression : self.expression,
  12375. property : prop
  12376. });
  12377. }
  12378. }
  12379. return self;
  12380. });
  12381. function literals_in_boolean_context(self, compressor) {
  12382. if (compressor.option("booleans") && compressor.in_boolean_context()) {
  12383. return make_node(AST_True, self);
  12384. }
  12385. return self;
  12386. };
  12387. OPT(AST_Array, literals_in_boolean_context);
  12388. OPT(AST_Object, literals_in_boolean_context);
  12389. OPT(AST_RegExp, literals_in_boolean_context);
  12390. })();
  12391. /***********************************************************************
  12392. A JavaScript tokenizer / parser / beautifier / compressor.
  12393. https://github.com/mishoo/UglifyJS2
  12394. -------------------------------- (C) ---------------------------------
  12395. Author: Mihai Bazon
  12396. <mihai.bazon@gmail.com>
  12397. http://mihai.bazon.net/blog
  12398. Distributed under the BSD license:
  12399. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  12400. Redistribution and use in source and binary forms, with or without
  12401. modification, are permitted provided that the following conditions
  12402. are met:
  12403. * Redistributions of source code must retain the above
  12404. copyright notice, this list of conditions and the following
  12405. disclaimer.
  12406. * Redistributions in binary form must reproduce the above
  12407. copyright notice, this list of conditions and the following
  12408. disclaimer in the documentation and/or other materials
  12409. provided with the distribution.
  12410. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  12411. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  12412. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  12413. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  12414. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  12415. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12416. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  12417. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  12418. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  12419. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  12420. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  12421. SUCH DAMAGE.
  12422. ***********************************************************************/
  12423. "use strict";
  12424. // a small wrapper around fitzgen's source-map library
  12425. function SourceMap(options) {
  12426. options = defaults(options, {
  12427. file : null,
  12428. root : null,
  12429. orig : null,
  12430. orig_line_diff : 0,
  12431. dest_line_diff : 0,
  12432. });
  12433. var generator = new MOZ_SourceMap.SourceMapGenerator({
  12434. file : options.file,
  12435. sourceRoot : options.root
  12436. });
  12437. var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
  12438. function add(source, gen_line, gen_col, orig_line, orig_col, name) {
  12439. if (orig_map) {
  12440. var info = orig_map.originalPositionFor({
  12441. line: orig_line,
  12442. column: orig_col
  12443. });
  12444. source = info.source;
  12445. orig_line = info.line;
  12446. orig_col = info.column;
  12447. name = info.name;
  12448. }
  12449. generator.addMapping({
  12450. generated : { line: gen_line + options.dest_line_diff, column: gen_col },
  12451. original : { line: orig_line + options.orig_line_diff, column: orig_col },
  12452. source : source,
  12453. name : name
  12454. });
  12455. };
  12456. return {
  12457. add : add,
  12458. get : function() { return generator },
  12459. toString : function() { return generator.toString() }
  12460. };
  12461. };
  12462. /***********************************************************************
  12463. A JavaScript tokenizer / parser / beautifier / compressor.
  12464. https://github.com/mishoo/UglifyJS2
  12465. -------------------------------- (C) ---------------------------------
  12466. Author: Mihai Bazon
  12467. <mihai.bazon@gmail.com>
  12468. http://mihai.bazon.net/blog
  12469. Distributed under the BSD license:
  12470. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  12471. Redistribution and use in source and binary forms, with or without
  12472. modification, are permitted provided that the following conditions
  12473. are met:
  12474. * Redistributions of source code must retain the above
  12475. copyright notice, this list of conditions and the following
  12476. disclaimer.
  12477. * Redistributions in binary form must reproduce the above
  12478. copyright notice, this list of conditions and the following
  12479. disclaimer in the documentation and/or other materials
  12480. provided with the distribution.
  12481. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  12482. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  12483. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  12484. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  12485. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  12486. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12487. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  12488. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  12489. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  12490. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  12491. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  12492. SUCH DAMAGE.
  12493. ***********************************************************************/
  12494. "use strict";
  12495. (function(){
  12496. var MOZ_TO_ME = {
  12497. TryStatement : function(M) {
  12498. return new AST_Try({
  12499. start : my_start_token(M),
  12500. end : my_end_token(M),
  12501. body : from_moz(M.block).body,
  12502. bcatch : from_moz(M.handlers[0]),
  12503. bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
  12504. });
  12505. },
  12506. CatchClause : function(M) {
  12507. return new AST_Catch({
  12508. start : my_start_token(M),
  12509. end : my_end_token(M),
  12510. argname : from_moz(M.param),
  12511. body : from_moz(M.body).body
  12512. });
  12513. },
  12514. ObjectExpression : function(M) {
  12515. return new AST_Object({
  12516. start : my_start_token(M),
  12517. end : my_end_token(M),
  12518. properties : M.properties.map(function(prop){
  12519. var key = prop.key;
  12520. var name = key.type == "Identifier" ? key.name : key.value;
  12521. var args = {
  12522. start : my_start_token(key),
  12523. end : my_end_token(prop.value),
  12524. key : name,
  12525. value : from_moz(prop.value)
  12526. };
  12527. switch (prop.kind) {
  12528. case "init":
  12529. return new AST_ObjectKeyVal(args);
  12530. case "set":
  12531. args.value.name = from_moz(key);
  12532. return new AST_ObjectSetter(args);
  12533. case "get":
  12534. args.value.name = from_moz(key);
  12535. return new AST_ObjectGetter(args);
  12536. }
  12537. })
  12538. });
  12539. },
  12540. SequenceExpression : function(M) {
  12541. return AST_Seq.from_array(M.expressions.map(from_moz));
  12542. },
  12543. MemberExpression : function(M) {
  12544. return new (M.computed ? AST_Sub : AST_Dot)({
  12545. start : my_start_token(M),
  12546. end : my_end_token(M),
  12547. property : M.computed ? from_moz(M.property) : M.property.name,
  12548. expression : from_moz(M.object)
  12549. });
  12550. },
  12551. SwitchCase : function(M) {
  12552. return new (M.test ? AST_Case : AST_Default)({
  12553. start : my_start_token(M),
  12554. end : my_end_token(M),
  12555. expression : from_moz(M.test),
  12556. body : M.consequent.map(from_moz)
  12557. });
  12558. },
  12559. Literal : function(M) {
  12560. var val = M.value, args = {
  12561. start : my_start_token(M),
  12562. end : my_end_token(M)
  12563. };
  12564. if (val === null) return new AST_Null(args);
  12565. switch (typeof val) {
  12566. case "string":
  12567. args.value = val;
  12568. return new AST_String(args);
  12569. case "number":
  12570. args.value = val;
  12571. return new AST_Number(args);
  12572. case "boolean":
  12573. return new (val ? AST_True : AST_False)(args);
  12574. default:
  12575. args.value = val;
  12576. return new AST_RegExp(args);
  12577. }
  12578. },
  12579. UnaryExpression: From_Moz_Unary,
  12580. UpdateExpression: From_Moz_Unary,
  12581. Identifier: function(M) {
  12582. var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
  12583. return new (M.name == "this" ? AST_This
  12584. : p.type == "LabeledStatement" ? AST_Label
  12585. : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
  12586. : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
  12587. : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
  12588. : p.type == "CatchClause" ? AST_SymbolCatch
  12589. : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
  12590. : AST_SymbolRef)({
  12591. start : my_start_token(M),
  12592. end : my_end_token(M),
  12593. name : M.name
  12594. });
  12595. }
  12596. };
  12597. function From_Moz_Unary(M) {
  12598. var prefix = "prefix" in M ? M.prefix
  12599. : M.type == "UnaryExpression" ? true : false;
  12600. return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
  12601. start : my_start_token(M),
  12602. end : my_end_token(M),
  12603. operator : M.operator,
  12604. expression : from_moz(M.argument)
  12605. });
  12606. };
  12607. var ME_TO_MOZ = {};
  12608. map("Node", AST_Node);
  12609. map("Program", AST_Toplevel, "body@body");
  12610. map("Function", AST_Function, "id>name, params@argnames, body%body");
  12611. map("EmptyStatement", AST_EmptyStatement);
  12612. map("BlockStatement", AST_BlockStatement, "body@body");
  12613. map("ExpressionStatement", AST_SimpleStatement, "expression>body");
  12614. map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
  12615. map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
  12616. map("BreakStatement", AST_Break, "label>label");
  12617. map("ContinueStatement", AST_Continue, "label>label");
  12618. map("WithStatement", AST_With, "object>expression, body>body");
  12619. map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
  12620. map("ReturnStatement", AST_Return, "argument>value");
  12621. map("ThrowStatement", AST_Throw, "argument>value");
  12622. map("WhileStatement", AST_While, "test>condition, body>body");
  12623. map("DoWhileStatement", AST_Do, "test>condition, body>body");
  12624. map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
  12625. map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
  12626. map("DebuggerStatement", AST_Debugger);
  12627. map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
  12628. map("VariableDeclaration", AST_Var, "declarations@definitions");
  12629. map("VariableDeclarator", AST_VarDef, "id>name, init>value");
  12630. map("ThisExpression", AST_This);
  12631. map("ArrayExpression", AST_Array, "elements@elements");
  12632. map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
  12633. map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
  12634. map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
  12635. map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
  12636. map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
  12637. map("NewExpression", AST_New, "callee>expression, arguments@args");
  12638. map("CallExpression", AST_Call, "callee>expression, arguments@args");
  12639. /* -----[ tools ]----- */
  12640. function my_start_token(moznode) {
  12641. return new AST_Token({
  12642. file : moznode.loc && moznode.loc.source,
  12643. line : moznode.loc && moznode.loc.start.line,
  12644. col : moznode.loc && moznode.loc.start.column,
  12645. pos : moznode.start,
  12646. endpos : moznode.start
  12647. });
  12648. };
  12649. function my_end_token(moznode) {
  12650. return new AST_Token({
  12651. file : moznode.loc && moznode.loc.source,
  12652. line : moznode.loc && moznode.loc.end.line,
  12653. col : moznode.loc && moznode.loc.end.column,
  12654. pos : moznode.end,
  12655. endpos : moznode.end
  12656. });
  12657. };
  12658. function map(moztype, mytype, propmap) {
  12659. var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
  12660. moz_to_me += "return new mytype({\n" +
  12661. "start: my_start_token(M),\n" +
  12662. "end: my_end_token(M)";
  12663. if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
  12664. var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
  12665. if (!m) throw new Error("Can't understand property map: " + prop);
  12666. var moz = "M." + m[1], how = m[2], my = m[3];
  12667. moz_to_me += ",\n" + my + ": ";
  12668. if (how == "@") {
  12669. moz_to_me += moz + ".map(from_moz)";
  12670. } else if (how == ">") {
  12671. moz_to_me += "from_moz(" + moz + ")";
  12672. } else if (how == "=") {
  12673. moz_to_me += moz;
  12674. } else if (how == "%") {
  12675. moz_to_me += "from_moz(" + moz + ").body";
  12676. } else throw new Error("Can't understand operator in propmap: " + prop);
  12677. });
  12678. moz_to_me += "\n})}";
  12679. // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
  12680. // console.log(moz_to_me);
  12681. moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
  12682. mytype, my_start_token, my_end_token, from_moz
  12683. );
  12684. return MOZ_TO_ME[moztype] = moz_to_me;
  12685. };
  12686. var FROM_MOZ_STACK = null;
  12687. function from_moz(node) {
  12688. FROM_MOZ_STACK.push(node);
  12689. var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
  12690. FROM_MOZ_STACK.pop();
  12691. return ret;
  12692. };
  12693. AST_Node.from_mozilla_ast = function(node){
  12694. var save_stack = FROM_MOZ_STACK;
  12695. FROM_MOZ_STACK = [];
  12696. var ast = from_moz(node);
  12697. FROM_MOZ_STACK = save_stack;
  12698. return ast;
  12699. };
  12700. })();
  12701. exports.sys = sys;
  12702. exports.MOZ_SourceMap = MOZ_SourceMap;
  12703. exports.UglifyJS = UglifyJS;
  12704. exports.array_to_hash = array_to_hash;
  12705. exports.slice = slice;
  12706. exports.characters = characters;
  12707. exports.member = member;
  12708. exports.find_if = find_if;
  12709. exports.repeat_string = repeat_string;
  12710. exports.DefaultsError = DefaultsError;
  12711. exports.defaults = defaults;
  12712. exports.merge = merge;
  12713. exports.noop = noop;
  12714. exports.MAP = MAP;
  12715. exports.push_uniq = push_uniq;
  12716. exports.string_template = string_template;
  12717. exports.remove = remove;
  12718. exports.mergeSort = mergeSort;
  12719. exports.set_difference = set_difference;
  12720. exports.set_intersection = set_intersection;
  12721. exports.makePredicate = makePredicate;
  12722. exports.all = all;
  12723. exports.Dictionary = Dictionary;
  12724. exports.DEFNODE = DEFNODE;
  12725. exports.AST_Token = AST_Token;
  12726. exports.AST_Node = AST_Node;
  12727. exports.AST_Statement = AST_Statement;
  12728. exports.AST_Debugger = AST_Debugger;
  12729. exports.AST_Directive = AST_Directive;
  12730. exports.AST_SimpleStatement = AST_SimpleStatement;
  12731. exports.walk_body = walk_body;
  12732. exports.AST_Block = AST_Block;
  12733. exports.AST_BlockStatement = AST_BlockStatement;
  12734. exports.AST_EmptyStatement = AST_EmptyStatement;
  12735. exports.AST_StatementWithBody = AST_StatementWithBody;
  12736. exports.AST_LabeledStatement = AST_LabeledStatement;
  12737. exports.AST_IterationStatement = AST_IterationStatement;
  12738. exports.AST_DWLoop = AST_DWLoop;
  12739. exports.AST_Do = AST_Do;
  12740. exports.AST_While = AST_While;
  12741. exports.AST_For = AST_For;
  12742. exports.AST_ForIn = AST_ForIn;
  12743. exports.AST_With = AST_With;
  12744. exports.AST_Scope = AST_Scope;
  12745. exports.AST_Toplevel = AST_Toplevel;
  12746. exports.AST_Lambda = AST_Lambda;
  12747. exports.AST_Accessor = AST_Accessor;
  12748. exports.AST_Function = AST_Function;
  12749. exports.AST_Defun = AST_Defun;
  12750. exports.AST_Jump = AST_Jump;
  12751. exports.AST_Exit = AST_Exit;
  12752. exports.AST_Return = AST_Return;
  12753. exports.AST_Throw = AST_Throw;
  12754. exports.AST_LoopControl = AST_LoopControl;
  12755. exports.AST_Break = AST_Break;
  12756. exports.AST_Continue = AST_Continue;
  12757. exports.AST_If = AST_If;
  12758. exports.AST_Switch = AST_Switch;
  12759. exports.AST_SwitchBranch = AST_SwitchBranch;
  12760. exports.AST_Default = AST_Default;
  12761. exports.AST_Case = AST_Case;
  12762. exports.AST_Try = AST_Try;
  12763. exports.AST_Catch = AST_Catch;
  12764. exports.AST_Finally = AST_Finally;
  12765. exports.AST_Definitions = AST_Definitions;
  12766. exports.AST_Var = AST_Var;
  12767. exports.AST_Const = AST_Const;
  12768. exports.AST_VarDef = AST_VarDef;
  12769. exports.AST_Call = AST_Call;
  12770. exports.AST_New = AST_New;
  12771. exports.AST_Seq = AST_Seq;
  12772. exports.AST_PropAccess = AST_PropAccess;
  12773. exports.AST_Dot = AST_Dot;
  12774. exports.AST_Sub = AST_Sub;
  12775. exports.AST_Unary = AST_Unary;
  12776. exports.AST_UnaryPrefix = AST_UnaryPrefix;
  12777. exports.AST_UnaryPostfix = AST_UnaryPostfix;
  12778. exports.AST_Binary = AST_Binary;
  12779. exports.AST_Conditional = AST_Conditional;
  12780. exports.AST_Assign = AST_Assign;
  12781. exports.AST_Array = AST_Array;
  12782. exports.AST_Object = AST_Object;
  12783. exports.AST_ObjectProperty = AST_ObjectProperty;
  12784. exports.AST_ObjectKeyVal = AST_ObjectKeyVal;
  12785. exports.AST_ObjectSetter = AST_ObjectSetter;
  12786. exports.AST_ObjectGetter = AST_ObjectGetter;
  12787. exports.AST_Symbol = AST_Symbol;
  12788. exports.AST_SymbolAccessor = AST_SymbolAccessor;
  12789. exports.AST_SymbolDeclaration = AST_SymbolDeclaration;
  12790. exports.AST_SymbolVar = AST_SymbolVar;
  12791. exports.AST_SymbolConst = AST_SymbolConst;
  12792. exports.AST_SymbolFunarg = AST_SymbolFunarg;
  12793. exports.AST_SymbolDefun = AST_SymbolDefun;
  12794. exports.AST_SymbolLambda = AST_SymbolLambda;
  12795. exports.AST_SymbolCatch = AST_SymbolCatch;
  12796. exports.AST_Label = AST_Label;
  12797. exports.AST_SymbolRef = AST_SymbolRef;
  12798. exports.AST_LabelRef = AST_LabelRef;
  12799. exports.AST_This = AST_This;
  12800. exports.AST_Constant = AST_Constant;
  12801. exports.AST_String = AST_String;
  12802. exports.AST_Number = AST_Number;
  12803. exports.AST_RegExp = AST_RegExp;
  12804. exports.AST_Atom = AST_Atom;
  12805. exports.AST_Null = AST_Null;
  12806. exports.AST_NaN = AST_NaN;
  12807. exports.AST_Undefined = AST_Undefined;
  12808. exports.AST_Hole = AST_Hole;
  12809. exports.AST_Infinity = AST_Infinity;
  12810. exports.AST_Boolean = AST_Boolean;
  12811. exports.AST_False = AST_False;
  12812. exports.AST_True = AST_True;
  12813. exports.TreeWalker = TreeWalker;
  12814. exports.KEYWORDS = KEYWORDS;
  12815. exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
  12816. exports.RESERVED_WORDS = RESERVED_WORDS;
  12817. exports.KEYWORDS_BEFORE_EXPRESSION = KEYWORDS_BEFORE_EXPRESSION;
  12818. exports.OPERATOR_CHARS = OPERATOR_CHARS;
  12819. exports.RE_HEX_NUMBER = RE_HEX_NUMBER;
  12820. exports.RE_OCT_NUMBER = RE_OCT_NUMBER;
  12821. exports.RE_DEC_NUMBER = RE_DEC_NUMBER;
  12822. exports.OPERATORS = OPERATORS;
  12823. exports.WHITESPACE_CHARS = WHITESPACE_CHARS;
  12824. exports.PUNC_BEFORE_EXPRESSION = PUNC_BEFORE_EXPRESSION;
  12825. exports.PUNC_CHARS = PUNC_CHARS;
  12826. exports.REGEXP_MODIFIERS = REGEXP_MODIFIERS;
  12827. exports.UNICODE = UNICODE;
  12828. exports.is_letter = is_letter;
  12829. exports.is_digit = is_digit;
  12830. exports.is_alphanumeric_char = is_alphanumeric_char;
  12831. exports.is_unicode_combining_mark = is_unicode_combining_mark;
  12832. exports.is_unicode_connector_punctuation = is_unicode_connector_punctuation;
  12833. exports.is_identifier = is_identifier;
  12834. exports.is_identifier_start = is_identifier_start;
  12835. exports.is_identifier_char = is_identifier_char;
  12836. exports.is_identifier_string = is_identifier_string;
  12837. exports.parse_js_number = parse_js_number;
  12838. exports.JS_Parse_Error = JS_Parse_Error;
  12839. exports.js_error = js_error;
  12840. exports.is_token = is_token;
  12841. exports.EX_EOF = EX_EOF;
  12842. exports.tokenizer = tokenizer;
  12843. exports.UNARY_PREFIX = UNARY_PREFIX;
  12844. exports.UNARY_POSTFIX = UNARY_POSTFIX;
  12845. exports.ASSIGNMENT = ASSIGNMENT;
  12846. exports.PRECEDENCE = PRECEDENCE;
  12847. exports.STATEMENTS_WITH_LABELS = STATEMENTS_WITH_LABELS;
  12848. exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
  12849. exports.parse = parse;
  12850. exports.TreeTransformer = TreeTransformer;
  12851. exports.SymbolDef = SymbolDef;
  12852. exports.base54 = base54;
  12853. exports.OutputStream = OutputStream;
  12854. exports.Compressor = Compressor;
  12855. exports.SourceMap = SourceMap;
  12856. exports.AST_Node.warn_function = function (txt) { if (typeof console != "undefined" && typeof console.warn === "function") console.warn(txt) }
  12857. exports.minify = function (files, options) {
  12858. options = UglifyJS.defaults(options, {
  12859. outSourceMap : null,
  12860. sourceRoot : null,
  12861. inSourceMap : null,
  12862. fromString : false,
  12863. warnings : false,
  12864. mangle : {},
  12865. output : null,
  12866. compress : {}
  12867. });
  12868. if (typeof files == "string")
  12869. files = [ files ];
  12870. UglifyJS.base54.reset();
  12871. // 1. parse
  12872. var toplevel = null;
  12873. files.forEach(function(file){
  12874. var code = options.fromString
  12875. ? file
  12876. : fs.readFileSync(file, "utf8");
  12877. toplevel = UglifyJS.parse(code, {
  12878. filename: options.fromString ? "?" : file,
  12879. toplevel: toplevel
  12880. });
  12881. });
  12882. // 2. compress
  12883. if (options.compress) {
  12884. var compress = { warnings: options.warnings };
  12885. UglifyJS.merge(compress, options.compress);
  12886. toplevel.figure_out_scope();
  12887. var sq = UglifyJS.Compressor(compress);
  12888. toplevel = toplevel.transform(sq);
  12889. }
  12890. // 3. mangle
  12891. if (options.mangle) {
  12892. toplevel.figure_out_scope();
  12893. toplevel.compute_char_frequency();
  12894. toplevel.mangle_names(options.mangle);
  12895. }
  12896. // 4. output
  12897. var inMap = options.inSourceMap;
  12898. var output = {};
  12899. if (typeof options.inSourceMap == "string") {
  12900. inMap = fs.readFileSync(options.inSourceMap, "utf8");
  12901. }
  12902. if (options.outSourceMap) {
  12903. output.source_map = UglifyJS.SourceMap({
  12904. file: options.outSourceMap,
  12905. orig: inMap,
  12906. root: options.sourceRoot
  12907. });
  12908. }
  12909. if (options.output) {
  12910. UglifyJS.merge(output, options.output);
  12911. }
  12912. var stream = UglifyJS.OutputStream(output);
  12913. toplevel.print(stream);
  12914. return {
  12915. code : stream + "",
  12916. map : output.source_map + ""
  12917. };
  12918. };
  12919. exports.describe_ast = function () {
  12920. var out = UglifyJS.OutputStream({ beautify: true });
  12921. function doitem(ctor) {
  12922. out.print("AST_" + ctor.TYPE);
  12923. var props = ctor.SELF_PROPS.filter(function(prop){
  12924. return !/^\$/.test(prop);
  12925. });
  12926. if (props.length > 0) {
  12927. out.space();
  12928. out.with_parens(function(){
  12929. props.forEach(function(prop, i){
  12930. if (i) out.space();
  12931. out.print(prop);
  12932. });
  12933. });
  12934. }
  12935. if (ctor.documentation) {
  12936. out.space();
  12937. out.print_string(ctor.documentation);
  12938. }
  12939. if (ctor.SUBCLASSES.length > 0) {
  12940. out.space();
  12941. out.with_block(function(){
  12942. ctor.SUBCLASSES.forEach(function(ctor, i){
  12943. out.indent();
  12944. doitem(ctor);
  12945. out.newline();
  12946. });
  12947. });
  12948. }
  12949. };
  12950. doitem(UglifyJS.AST_Node);
  12951. return out + "";
  12952. };
  12953. },{"source-map":35,"util":32}],46:[function(require,module,exports){
  12954. var uglify = require('uglify-js')
  12955. var globalVars = require('./vars')
  12956. module.exports = addWith
  12957. function addWith(obj, src, exclude, environments) {
  12958. environments = environments || ['reservedVars', 'ecmaIdentifiers', 'nonstandard', 'node']
  12959. exclude = exclude || []
  12960. exclude = exclude.concat(detect(obj))
  12961. var vars = detect('(function () {' + src + '}())')//allows the `return` keyword
  12962. .filter(function (v) {
  12963. for (var i = 0; i < environments.length; i++) {
  12964. if (v in globalVars[environments[i]]) {
  12965. return false;
  12966. }
  12967. }
  12968. return exclude.indexOf(v) === -1
  12969. })
  12970. if (vars.length === 0) return src
  12971. var declareLocal = ''
  12972. var local = 'locals'
  12973. if (/^[a-zA-Z0-9$_]+$/.test(obj)) {
  12974. local = obj
  12975. } else {
  12976. while (vars.indexOf(local) != -1 || exclude.indexOf(local) != -1) {
  12977. local += '_'
  12978. }
  12979. declareLocal = local + ' = (' + obj + '),'
  12980. }
  12981. return 'var ' + declareLocal + vars
  12982. .map(function (v) {
  12983. return v + ' = ' + local + '.' + v
  12984. }).join(',') + ';' + src
  12985. }
  12986. function detect(src) {
  12987. var ast = uglify.parse(src.toString())
  12988. ast.figure_out_scope()
  12989. var globals = ast.globals
  12990. .map(function (node, name) {
  12991. return name
  12992. })
  12993. return globals;
  12994. }
  12995. },{"./vars":58,"uglify-js":57}],47:[function(require,module,exports){
  12996. arguments[4][35][0].apply(exports,arguments)
  12997. },{"./source-map/source-map-consumer":52,"./source-map/source-map-generator":53,"./source-map/source-node":54}],48:[function(require,module,exports){
  12998. arguments[4][36][0].apply(exports,arguments)
  12999. },{"./util":55,"amdefine":56}],49:[function(require,module,exports){
  13000. arguments[4][37][0].apply(exports,arguments)
  13001. },{"./base64":50,"amdefine":56}],50:[function(require,module,exports){
  13002. arguments[4][38][0].apply(exports,arguments)
  13003. },{"amdefine":56}],51:[function(require,module,exports){
  13004. arguments[4][39][0].apply(exports,arguments)
  13005. },{"amdefine":56}],52:[function(require,module,exports){
  13006. arguments[4][40][0].apply(exports,arguments)
  13007. },{"./array-set":48,"./base64-vlq":49,"./binary-search":51,"./util":55,"amdefine":56}],53:[function(require,module,exports){
  13008. arguments[4][41][0].apply(exports,arguments)
  13009. },{"./array-set":48,"./base64-vlq":49,"./util":55,"amdefine":56}],54:[function(require,module,exports){
  13010. arguments[4][42][0].apply(exports,arguments)
  13011. },{"./source-map-generator":53,"./util":55,"amdefine":56}],55:[function(require,module,exports){
  13012. arguments[4][43][0].apply(exports,arguments)
  13013. },{"amdefine":56}],56:[function(require,module,exports){
  13014. var process=require("__browserify_process"),__filename="/../node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js";/** vim: et:ts=4:sw=4:sts=4
  13015. * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
  13016. * Available via the MIT or new BSD license.
  13017. * see: http://github.com/jrburke/amdefine for details
  13018. */
  13019. /*jslint node: true */
  13020. /*global module, process */
  13021. 'use strict';
  13022. /**
  13023. * Creates a define for node.
  13024. * @param {Object} module the "module" object that is defined by Node for the
  13025. * current module.
  13026. * @param {Function} [requireFn]. Node's require function for the current module.
  13027. * It only needs to be passed in Node versions before 0.5, when module.require
  13028. * did not exist.
  13029. * @returns {Function} a define function that is usable for the current node
  13030. * module.
  13031. */
  13032. function amdefine(module, requireFn) {
  13033. 'use strict';
  13034. var defineCache = {},
  13035. loaderCache = {},
  13036. alreadyCalled = false,
  13037. path = require('path'),
  13038. makeRequire, stringRequire;
  13039. /**
  13040. * Trims the . and .. from an array of path segments.
  13041. * It will keep a leading path segment if a .. will become
  13042. * the first path segment, to help with module name lookups,
  13043. * which act like paths, but can be remapped. But the end result,
  13044. * all paths that use this function should look normalized.
  13045. * NOTE: this method MODIFIES the input array.
  13046. * @param {Array} ary the array of path segments.
  13047. */
  13048. function trimDots(ary) {
  13049. var i, part;
  13050. for (i = 0; ary[i]; i+= 1) {
  13051. part = ary[i];
  13052. if (part === '.') {
  13053. ary.splice(i, 1);
  13054. i -= 1;
  13055. } else if (part === '..') {
  13056. if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
  13057. //End of the line. Keep at least one non-dot
  13058. //path segment at the front so it can be mapped
  13059. //correctly to disk. Otherwise, there is likely
  13060. //no path mapping for a path starting with '..'.
  13061. //This can still fail, but catches the most reasonable
  13062. //uses of ..
  13063. break;
  13064. } else if (i > 0) {
  13065. ary.splice(i - 1, 2);
  13066. i -= 2;
  13067. }
  13068. }
  13069. }
  13070. }
  13071. function normalize(name, baseName) {
  13072. var baseParts;
  13073. //Adjust any relative paths.
  13074. if (name && name.charAt(0) === '.') {
  13075. //If have a base name, try to normalize against it,
  13076. //otherwise, assume it is a top-level require that will
  13077. //be relative to baseUrl in the end.
  13078. if (baseName) {
  13079. baseParts = baseName.split('/');
  13080. baseParts = baseParts.slice(0, baseParts.length - 1);
  13081. baseParts = baseParts.concat(name.split('/'));
  13082. trimDots(baseParts);
  13083. name = baseParts.join('/');
  13084. }
  13085. }
  13086. return name;
  13087. }
  13088. /**
  13089. * Create the normalize() function passed to a loader plugin's
  13090. * normalize method.
  13091. */
  13092. function makeNormalize(relName) {
  13093. return function (name) {
  13094. return normalize(name, relName);
  13095. };
  13096. }
  13097. function makeLoad(id) {
  13098. function load(value) {
  13099. loaderCache[id] = value;
  13100. }
  13101. load.fromText = function (id, text) {
  13102. //This one is difficult because the text can/probably uses
  13103. //define, and any relative paths and requires should be relative
  13104. //to that id was it would be found on disk. But this would require
  13105. //bootstrapping a module/require fairly deeply from node core.
  13106. //Not sure how best to go about that yet.
  13107. throw new Error('amdefine does not implement load.fromText');
  13108. };
  13109. return load;
  13110. }
  13111. makeRequire = function (systemRequire, exports, module, relId) {
  13112. function amdRequire(deps, callback) {
  13113. if (typeof deps === 'string') {
  13114. //Synchronous, single module require('')
  13115. return stringRequire(systemRequire, exports, module, deps, relId);
  13116. } else {
  13117. //Array of dependencies with a callback.
  13118. //Convert the dependencies to modules.
  13119. deps = deps.map(function (depName) {
  13120. return stringRequire(systemRequire, exports, module, depName, relId);
  13121. });
  13122. //Wait for next tick to call back the require call.
  13123. process.nextTick(function () {
  13124. callback.apply(null, deps);
  13125. });
  13126. }
  13127. }
  13128. amdRequire.toUrl = function (filePath) {
  13129. if (filePath.indexOf('.') === 0) {
  13130. return normalize(filePath, path.dirname(module.filename));
  13131. } else {
  13132. return filePath;
  13133. }
  13134. };
  13135. return amdRequire;
  13136. };
  13137. //Favor explicit value, passed in if the module wants to support Node 0.4.
  13138. requireFn = requireFn || function req() {
  13139. return module.require.apply(module, arguments);
  13140. };
  13141. function runFactory(id, deps, factory) {
  13142. var r, e, m, result;
  13143. if (id) {
  13144. e = loaderCache[id] = {};
  13145. m = {
  13146. id: id,
  13147. uri: __filename,
  13148. exports: e
  13149. };
  13150. r = makeRequire(requireFn, e, m, id);
  13151. } else {
  13152. //Only support one define call per file
  13153. if (alreadyCalled) {
  13154. throw new Error('amdefine with no module ID cannot be called more than once per file.');
  13155. }
  13156. alreadyCalled = true;
  13157. //Use the real variables from node
  13158. //Use module.exports for exports, since
  13159. //the exports in here is amdefine exports.
  13160. e = module.exports;
  13161. m = module;
  13162. r = makeRequire(requireFn, e, m, module.id);
  13163. }
  13164. //If there are dependencies, they are strings, so need
  13165. //to convert them to dependency values.
  13166. if (deps) {
  13167. deps = deps.map(function (depName) {
  13168. return r(depName);
  13169. });
  13170. }
  13171. //Call the factory with the right dependencies.
  13172. if (typeof factory === 'function') {
  13173. result = factory.apply(m.exports, deps);
  13174. } else {
  13175. result = factory;
  13176. }
  13177. if (result !== undefined) {
  13178. m.exports = result;
  13179. if (id) {
  13180. loaderCache[id] = m.exports;
  13181. }
  13182. }
  13183. }
  13184. stringRequire = function (systemRequire, exports, module, id, relId) {
  13185. //Split the ID by a ! so that
  13186. var index = id.indexOf('!'),
  13187. originalId = id,
  13188. prefix, plugin;
  13189. if (index === -1) {
  13190. id = normalize(id, relId);
  13191. //Straight module lookup. If it is one of the special dependencies,
  13192. //deal with it, otherwise, delegate to node.
  13193. if (id === 'require') {
  13194. return makeRequire(systemRequire, exports, module, relId);
  13195. } else if (id === 'exports') {
  13196. return exports;
  13197. } else if (id === 'module') {
  13198. return module;
  13199. } else if (loaderCache.hasOwnProperty(id)) {
  13200. return loaderCache[id];
  13201. } else if (defineCache[id]) {
  13202. runFactory.apply(null, defineCache[id]);
  13203. return loaderCache[id];
  13204. } else {
  13205. if(systemRequire) {
  13206. return systemRequire(originalId);
  13207. } else {
  13208. throw new Error('No module with ID: ' + id);
  13209. }
  13210. }
  13211. } else {
  13212. //There is a plugin in play.
  13213. prefix = id.substring(0, index);
  13214. id = id.substring(index + 1, id.length);
  13215. plugin = stringRequire(systemRequire, exports, module, prefix, relId);
  13216. if (plugin.normalize) {
  13217. id = plugin.normalize(id, makeNormalize(relId));
  13218. } else {
  13219. //Normalize the ID normally.
  13220. id = normalize(id, relId);
  13221. }
  13222. if (loaderCache[id]) {
  13223. return loaderCache[id];
  13224. } else {
  13225. plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
  13226. return loaderCache[id];
  13227. }
  13228. }
  13229. };
  13230. //Create a define function specific to the module asking for amdefine.
  13231. function define(id, deps, factory) {
  13232. if (Array.isArray(id)) {
  13233. factory = deps;
  13234. deps = id;
  13235. id = undefined;
  13236. } else if (typeof id !== 'string') {
  13237. factory = id;
  13238. id = deps = undefined;
  13239. }
  13240. if (deps && !Array.isArray(deps)) {
  13241. factory = deps;
  13242. deps = undefined;
  13243. }
  13244. if (!deps) {
  13245. deps = ['require', 'exports', 'module'];
  13246. }
  13247. //Set up properties for this module. If an ID, then use
  13248. //internal cache. If no ID, then use the external variables
  13249. //for this node module.
  13250. if (id) {
  13251. //Put the module in deep freeze until there is a
  13252. //require call for it.
  13253. defineCache[id] = [id, deps, factory];
  13254. } else {
  13255. runFactory(id, deps, factory);
  13256. }
  13257. }
  13258. //define.require, which has access to all the values in the
  13259. //cache. Useful for AMD modules that all have IDs in the file,
  13260. //but need to finally export a value to node based on one of those
  13261. //IDs.
  13262. define.require = function (id) {
  13263. if (loaderCache[id]) {
  13264. return loaderCache[id];
  13265. }
  13266. if (defineCache[id]) {
  13267. runFactory.apply(null, defineCache[id]);
  13268. return loaderCache[id];
  13269. }
  13270. };
  13271. define.amd = {};
  13272. return define;
  13273. }
  13274. module.exports = amdefine;
  13275. },{"__browserify_process":29,"path":30}],57:[function(require,module,exports){
  13276. var sys = require("util");
  13277. var MOZ_SourceMap = require("source-map");
  13278. var UglifyJS = exports;
  13279. /***********************************************************************
  13280. A JavaScript tokenizer / parser / beautifier / compressor.
  13281. https://github.com/mishoo/UglifyJS2
  13282. -------------------------------- (C) ---------------------------------
  13283. Author: Mihai Bazon
  13284. <mihai.bazon@gmail.com>
  13285. http://mihai.bazon.net/blog
  13286. Distributed under the BSD license:
  13287. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  13288. Redistribution and use in source and binary forms, with or without
  13289. modification, are permitted provided that the following conditions
  13290. are met:
  13291. * Redistributions of source code must retain the above
  13292. copyright notice, this list of conditions and the following
  13293. disclaimer.
  13294. * Redistributions in binary form must reproduce the above
  13295. copyright notice, this list of conditions and the following
  13296. disclaimer in the documentation and/or other materials
  13297. provided with the distribution.
  13298. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  13299. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13300. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  13301. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  13302. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  13303. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  13304. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  13305. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13306. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  13307. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  13308. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  13309. SUCH DAMAGE.
  13310. ***********************************************************************/
  13311. "use strict";
  13312. function array_to_hash(a) {
  13313. var ret = Object.create(null);
  13314. for (var i = 0; i < a.length; ++i)
  13315. ret[a[i]] = true;
  13316. return ret;
  13317. };
  13318. function slice(a, start) {
  13319. return Array.prototype.slice.call(a, start || 0);
  13320. };
  13321. function characters(str) {
  13322. return str.split("");
  13323. };
  13324. function member(name, array) {
  13325. for (var i = array.length; --i >= 0;)
  13326. if (array[i] == name)
  13327. return true;
  13328. return false;
  13329. };
  13330. function find_if(func, array) {
  13331. for (var i = 0, n = array.length; i < n; ++i) {
  13332. if (func(array[i]))
  13333. return array[i];
  13334. }
  13335. };
  13336. function repeat_string(str, i) {
  13337. if (i <= 0) return "";
  13338. if (i == 1) return str;
  13339. var d = repeat_string(str, i >> 1);
  13340. d += d;
  13341. if (i & 1) d += str;
  13342. return d;
  13343. };
  13344. function DefaultsError(msg, defs) {
  13345. this.msg = msg;
  13346. this.defs = defs;
  13347. };
  13348. function defaults(args, defs, croak) {
  13349. if (args === true)
  13350. args = {};
  13351. var ret = args || {};
  13352. if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
  13353. throw new DefaultsError("`" + i + "` is not a supported option", defs);
  13354. for (var i in defs) if (defs.hasOwnProperty(i)) {
  13355. ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
  13356. }
  13357. return ret;
  13358. };
  13359. function merge(obj, ext) {
  13360. for (var i in ext) if (ext.hasOwnProperty(i)) {
  13361. obj[i] = ext[i];
  13362. }
  13363. return obj;
  13364. };
  13365. function noop() {};
  13366. var MAP = (function(){
  13367. function MAP(a, f, backwards) {
  13368. var ret = [], top = [], i;
  13369. function doit() {
  13370. var val = f(a[i], i);
  13371. var is_last = val instanceof Last;
  13372. if (is_last) val = val.v;
  13373. if (val instanceof AtTop) {
  13374. val = val.v;
  13375. if (val instanceof Splice) {
  13376. top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
  13377. } else {
  13378. top.push(val);
  13379. }
  13380. }
  13381. else if (val !== skip) {
  13382. if (val instanceof Splice) {
  13383. ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
  13384. } else {
  13385. ret.push(val);
  13386. }
  13387. }
  13388. return is_last;
  13389. };
  13390. if (a instanceof Array) {
  13391. if (backwards) {
  13392. for (i = a.length; --i >= 0;) if (doit()) break;
  13393. ret.reverse();
  13394. top.reverse();
  13395. } else {
  13396. for (i = 0; i < a.length; ++i) if (doit()) break;
  13397. }
  13398. }
  13399. else {
  13400. for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
  13401. }
  13402. return top.concat(ret);
  13403. };
  13404. MAP.at_top = function(val) { return new AtTop(val) };
  13405. MAP.splice = function(val) { return new Splice(val) };
  13406. MAP.last = function(val) { return new Last(val) };
  13407. var skip = MAP.skip = {};
  13408. function AtTop(val) { this.v = val };
  13409. function Splice(val) { this.v = val };
  13410. function Last(val) { this.v = val };
  13411. return MAP;
  13412. })();
  13413. function push_uniq(array, el) {
  13414. if (array.indexOf(el) < 0)
  13415. array.push(el);
  13416. };
  13417. function string_template(text, props) {
  13418. return text.replace(/\{(.+?)\}/g, function(str, p){
  13419. return props[p];
  13420. });
  13421. };
  13422. function remove(array, el) {
  13423. for (var i = array.length; --i >= 0;) {
  13424. if (array[i] === el) array.splice(i, 1);
  13425. }
  13426. };
  13427. function mergeSort(array, cmp) {
  13428. if (array.length < 2) return array.slice();
  13429. function merge(a, b) {
  13430. var r = [], ai = 0, bi = 0, i = 0;
  13431. while (ai < a.length && bi < b.length) {
  13432. cmp(a[ai], b[bi]) <= 0
  13433. ? r[i++] = a[ai++]
  13434. : r[i++] = b[bi++];
  13435. }
  13436. if (ai < a.length) r.push.apply(r, a.slice(ai));
  13437. if (bi < b.length) r.push.apply(r, b.slice(bi));
  13438. return r;
  13439. };
  13440. function _ms(a) {
  13441. if (a.length <= 1)
  13442. return a;
  13443. var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
  13444. left = _ms(left);
  13445. right = _ms(right);
  13446. return merge(left, right);
  13447. };
  13448. return _ms(array);
  13449. };
  13450. function set_difference(a, b) {
  13451. return a.filter(function(el){
  13452. return b.indexOf(el) < 0;
  13453. });
  13454. };
  13455. function set_intersection(a, b) {
  13456. return a.filter(function(el){
  13457. return b.indexOf(el) >= 0;
  13458. });
  13459. };
  13460. // this function is taken from Acorn [1], written by Marijn Haverbeke
  13461. // [1] https://github.com/marijnh/acorn
  13462. function makePredicate(words) {
  13463. if (!(words instanceof Array)) words = words.split(" ");
  13464. var f = "", cats = [];
  13465. out: for (var i = 0; i < words.length; ++i) {
  13466. for (var j = 0; j < cats.length; ++j)
  13467. if (cats[j][0].length == words[i].length) {
  13468. cats[j].push(words[i]);
  13469. continue out;
  13470. }
  13471. cats.push([words[i]]);
  13472. }
  13473. function compareTo(arr) {
  13474. if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
  13475. f += "switch(str){";
  13476. for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
  13477. f += "return true}return false;";
  13478. }
  13479. // When there are more than three length categories, an outer
  13480. // switch first dispatches on the lengths, to save on comparisons.
  13481. if (cats.length > 3) {
  13482. cats.sort(function(a, b) {return b.length - a.length;});
  13483. f += "switch(str.length){";
  13484. for (var i = 0; i < cats.length; ++i) {
  13485. var cat = cats[i];
  13486. f += "case " + cat[0].length + ":";
  13487. compareTo(cat);
  13488. }
  13489. f += "}";
  13490. // Otherwise, simply generate a flat `switch` statement.
  13491. } else {
  13492. compareTo(words);
  13493. }
  13494. return new Function("str", f);
  13495. };
  13496. function all(array, predicate) {
  13497. for (var i = array.length; --i >= 0;)
  13498. if (!predicate(array[i]))
  13499. return false;
  13500. return true;
  13501. };
  13502. function Dictionary() {
  13503. this._values = Object.create(null);
  13504. this._size = 0;
  13505. };
  13506. Dictionary.prototype = {
  13507. set: function(key, val) {
  13508. if (!this.has(key)) ++this._size;
  13509. this._values["$" + key] = val;
  13510. return this;
  13511. },
  13512. add: function(key, val) {
  13513. if (this.has(key)) {
  13514. this.get(key).push(val);
  13515. } else {
  13516. this.set(key, [ val ]);
  13517. }
  13518. return this;
  13519. },
  13520. get: function(key) { return this._values["$" + key] },
  13521. del: function(key) {
  13522. if (this.has(key)) {
  13523. --this._size;
  13524. delete this._values["$" + key];
  13525. }
  13526. return this;
  13527. },
  13528. has: function(key) { return ("$" + key) in this._values },
  13529. each: function(f) {
  13530. for (var i in this._values)
  13531. f(this._values[i], i.substr(1));
  13532. },
  13533. size: function() {
  13534. return this._size;
  13535. },
  13536. map: function(f) {
  13537. var ret = [];
  13538. for (var i in this._values)
  13539. ret.push(f(this._values[i], i.substr(1)));
  13540. return ret;
  13541. }
  13542. };
  13543. /***********************************************************************
  13544. A JavaScript tokenizer / parser / beautifier / compressor.
  13545. https://github.com/mishoo/UglifyJS2
  13546. -------------------------------- (C) ---------------------------------
  13547. Author: Mihai Bazon
  13548. <mihai.bazon@gmail.com>
  13549. http://mihai.bazon.net/blog
  13550. Distributed under the BSD license:
  13551. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  13552. Redistribution and use in source and binary forms, with or without
  13553. modification, are permitted provided that the following conditions
  13554. are met:
  13555. * Redistributions of source code must retain the above
  13556. copyright notice, this list of conditions and the following
  13557. disclaimer.
  13558. * Redistributions in binary form must reproduce the above
  13559. copyright notice, this list of conditions and the following
  13560. disclaimer in the documentation and/or other materials
  13561. provided with the distribution.
  13562. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  13563. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13564. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  13565. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  13566. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  13567. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  13568. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  13569. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13570. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  13571. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  13572. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  13573. SUCH DAMAGE.
  13574. ***********************************************************************/
  13575. "use strict";
  13576. function DEFNODE(type, props, methods, base) {
  13577. if (arguments.length < 4) base = AST_Node;
  13578. if (!props) props = [];
  13579. else props = props.split(/\s+/);
  13580. var self_props = props;
  13581. if (base && base.PROPS)
  13582. props = props.concat(base.PROPS);
  13583. var code = "return function AST_" + type + "(props){ if (props) { ";
  13584. for (var i = props.length; --i >= 0;) {
  13585. code += "this." + props[i] + " = props." + props[i] + ";";
  13586. }
  13587. var proto = base && new base;
  13588. if (proto && proto.initialize || (methods && methods.initialize))
  13589. code += "this.initialize();";
  13590. code += "}}";
  13591. var ctor = new Function(code)();
  13592. if (proto) {
  13593. ctor.prototype = proto;
  13594. ctor.BASE = base;
  13595. }
  13596. if (base) base.SUBCLASSES.push(ctor);
  13597. ctor.prototype.CTOR = ctor;
  13598. ctor.PROPS = props || null;
  13599. ctor.SELF_PROPS = self_props;
  13600. ctor.SUBCLASSES = [];
  13601. if (type) {
  13602. ctor.prototype.TYPE = ctor.TYPE = type;
  13603. }
  13604. if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
  13605. if (/^\$/.test(i)) {
  13606. ctor[i.substr(1)] = methods[i];
  13607. } else {
  13608. ctor.prototype[i] = methods[i];
  13609. }
  13610. }
  13611. ctor.DEFMETHOD = function(name, method) {
  13612. this.prototype[name] = method;
  13613. };
  13614. return ctor;
  13615. };
  13616. var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {
  13617. }, null);
  13618. var AST_Node = DEFNODE("Node", "start end", {
  13619. clone: function() {
  13620. return new this.CTOR(this);
  13621. },
  13622. $documentation: "Base class of all AST nodes",
  13623. $propdoc: {
  13624. start: "[AST_Token] The first token of this node",
  13625. end: "[AST_Token] The last token of this node"
  13626. },
  13627. _walk: function(visitor) {
  13628. return visitor._visit(this);
  13629. },
  13630. walk: function(visitor) {
  13631. return this._walk(visitor); // not sure the indirection will be any help
  13632. }
  13633. }, null);
  13634. AST_Node.warn_function = null;
  13635. AST_Node.warn = function(txt, props) {
  13636. if (AST_Node.warn_function)
  13637. AST_Node.warn_function(string_template(txt, props));
  13638. };
  13639. /* -----[ statements ]----- */
  13640. var AST_Statement = DEFNODE("Statement", null, {
  13641. $documentation: "Base class of all statements",
  13642. });
  13643. var AST_Debugger = DEFNODE("Debugger", null, {
  13644. $documentation: "Represents a debugger statement",
  13645. }, AST_Statement);
  13646. var AST_Directive = DEFNODE("Directive", "value scope", {
  13647. $documentation: "Represents a directive, like \"use strict\";",
  13648. $propdoc: {
  13649. value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
  13650. scope: "[AST_Scope/S] The scope that this directive affects"
  13651. },
  13652. }, AST_Statement);
  13653. var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
  13654. $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
  13655. $propdoc: {
  13656. body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
  13657. },
  13658. _walk: function(visitor) {
  13659. return visitor._visit(this, function(){
  13660. this.body._walk(visitor);
  13661. });
  13662. }
  13663. }, AST_Statement);
  13664. function walk_body(node, visitor) {
  13665. if (node.body instanceof AST_Statement) {
  13666. node.body._walk(visitor);
  13667. }
  13668. else node.body.forEach(function(stat){
  13669. stat._walk(visitor);
  13670. });
  13671. };
  13672. var AST_Block = DEFNODE("Block", "body", {
  13673. $documentation: "A body of statements (usually bracketed)",
  13674. $propdoc: {
  13675. body: "[AST_Statement*] an array of statements"
  13676. },
  13677. _walk: function(visitor) {
  13678. return visitor._visit(this, function(){
  13679. walk_body(this, visitor);
  13680. });
  13681. }
  13682. }, AST_Statement);
  13683. var AST_BlockStatement = DEFNODE("BlockStatement", null, {
  13684. $documentation: "A block statement",
  13685. }, AST_Block);
  13686. var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
  13687. $documentation: "The empty statement (empty block or simply a semicolon)",
  13688. _walk: function(visitor) {
  13689. return visitor._visit(this);
  13690. }
  13691. }, AST_Statement);
  13692. var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
  13693. $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
  13694. $propdoc: {
  13695. body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
  13696. },
  13697. _walk: function(visitor) {
  13698. return visitor._visit(this, function(){
  13699. this.body._walk(visitor);
  13700. });
  13701. }
  13702. }, AST_Statement);
  13703. var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
  13704. $documentation: "Statement with a label",
  13705. $propdoc: {
  13706. label: "[AST_Label] a label definition"
  13707. },
  13708. _walk: function(visitor) {
  13709. return visitor._visit(this, function(){
  13710. this.label._walk(visitor);
  13711. this.body._walk(visitor);
  13712. });
  13713. }
  13714. }, AST_StatementWithBody);
  13715. var AST_DWLoop = DEFNODE("DWLoop", "condition", {
  13716. $documentation: "Base class for do/while statements",
  13717. $propdoc: {
  13718. condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
  13719. },
  13720. _walk: function(visitor) {
  13721. return visitor._visit(this, function(){
  13722. this.condition._walk(visitor);
  13723. this.body._walk(visitor);
  13724. });
  13725. }
  13726. }, AST_StatementWithBody);
  13727. var AST_Do = DEFNODE("Do", null, {
  13728. $documentation: "A `do` statement",
  13729. }, AST_DWLoop);
  13730. var AST_While = DEFNODE("While", null, {
  13731. $documentation: "A `while` statement",
  13732. }, AST_DWLoop);
  13733. var AST_For = DEFNODE("For", "init condition step", {
  13734. $documentation: "A `for` statement",
  13735. $propdoc: {
  13736. init: "[AST_Node?] the `for` initialization code, or null if empty",
  13737. condition: "[AST_Node?] the `for` termination clause, or null if empty",
  13738. step: "[AST_Node?] the `for` update clause, or null if empty"
  13739. },
  13740. _walk: function(visitor) {
  13741. return visitor._visit(this, function(){
  13742. if (this.init) this.init._walk(visitor);
  13743. if (this.condition) this.condition._walk(visitor);
  13744. if (this.step) this.step._walk(visitor);
  13745. this.body._walk(visitor);
  13746. });
  13747. }
  13748. }, AST_StatementWithBody);
  13749. var AST_ForIn = DEFNODE("ForIn", "init name object", {
  13750. $documentation: "A `for ... in` statement",
  13751. $propdoc: {
  13752. init: "[AST_Node] the `for/in` initialization code",
  13753. name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
  13754. object: "[AST_Node] the object that we're looping through"
  13755. },
  13756. _walk: function(visitor) {
  13757. return visitor._visit(this, function(){
  13758. this.init._walk(visitor);
  13759. this.object._walk(visitor);
  13760. this.body._walk(visitor);
  13761. });
  13762. }
  13763. }, AST_StatementWithBody);
  13764. var AST_With = DEFNODE("With", "expression", {
  13765. $documentation: "A `with` statement",
  13766. $propdoc: {
  13767. expression: "[AST_Node] the `with` expression"
  13768. },
  13769. _walk: function(visitor) {
  13770. return visitor._visit(this, function(){
  13771. this.expression._walk(visitor);
  13772. this.body._walk(visitor);
  13773. });
  13774. }
  13775. }, AST_StatementWithBody);
  13776. /* -----[ scope and functions ]----- */
  13777. var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
  13778. $documentation: "Base class for all statements introducing a lexical scope",
  13779. $propdoc: {
  13780. directives: "[string*/S] an array of directives declared in this scope",
  13781. variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
  13782. functions: "[Object/S] like `variables`, but only lists function declarations",
  13783. uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
  13784. uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
  13785. parent_scope: "[AST_Scope?/S] link to the parent scope",
  13786. enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
  13787. cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
  13788. },
  13789. }, AST_Block);
  13790. var AST_Toplevel = DEFNODE("Toplevel", "globals", {
  13791. $documentation: "The toplevel scope",
  13792. $propdoc: {
  13793. globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
  13794. },
  13795. wrap_enclose: function(arg_parameter_pairs) {
  13796. var self = this;
  13797. var args = [];
  13798. var parameters = [];
  13799. arg_parameter_pairs.forEach(function(pair) {
  13800. var split = pair.split(":");
  13801. args.push(split[0]);
  13802. parameters.push(split[1]);
  13803. });
  13804. var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
  13805. wrapped_tl = parse(wrapped_tl);
  13806. wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
  13807. if (node instanceof AST_Directive && node.value == "$ORIG") {
  13808. return MAP.splice(self.body);
  13809. }
  13810. }));
  13811. return wrapped_tl;
  13812. },
  13813. wrap_commonjs: function(name, export_all) {
  13814. var self = this;
  13815. var to_export = [];
  13816. if (export_all) {
  13817. self.figure_out_scope();
  13818. self.walk(new TreeWalker(function(node){
  13819. if (node instanceof AST_SymbolDeclaration && node.definition().global) {
  13820. if (!find_if(function(n){ return n.name == node.name }, to_export))
  13821. to_export.push(node);
  13822. }
  13823. }));
  13824. }
  13825. var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
  13826. wrapped_tl = parse(wrapped_tl);
  13827. wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
  13828. if (node instanceof AST_SimpleStatement) {
  13829. node = node.body;
  13830. if (node instanceof AST_String) switch (node.getValue()) {
  13831. case "$ORIG":
  13832. return MAP.splice(self.body);
  13833. case "$EXPORTS":
  13834. var body = [];
  13835. to_export.forEach(function(sym){
  13836. body.push(new AST_SimpleStatement({
  13837. body: new AST_Assign({
  13838. left: new AST_Sub({
  13839. expression: new AST_SymbolRef({ name: "exports" }),
  13840. property: new AST_String({ value: sym.name }),
  13841. }),
  13842. operator: "=",
  13843. right: new AST_SymbolRef(sym),
  13844. }),
  13845. }));
  13846. });
  13847. return MAP.splice(body);
  13848. }
  13849. }
  13850. }));
  13851. return wrapped_tl;
  13852. }
  13853. }, AST_Scope);
  13854. var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
  13855. $documentation: "Base class for functions",
  13856. $propdoc: {
  13857. name: "[AST_SymbolDeclaration?] the name of this function",
  13858. argnames: "[AST_SymbolFunarg*] array of function arguments",
  13859. uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
  13860. },
  13861. _walk: function(visitor) {
  13862. return visitor._visit(this, function(){
  13863. if (this.name) this.name._walk(visitor);
  13864. this.argnames.forEach(function(arg){
  13865. arg._walk(visitor);
  13866. });
  13867. walk_body(this, visitor);
  13868. });
  13869. }
  13870. }, AST_Scope);
  13871. var AST_Accessor = DEFNODE("Accessor", null, {
  13872. $documentation: "A setter/getter function"
  13873. }, AST_Lambda);
  13874. var AST_Function = DEFNODE("Function", null, {
  13875. $documentation: "A function expression"
  13876. }, AST_Lambda);
  13877. var AST_Defun = DEFNODE("Defun", null, {
  13878. $documentation: "A function definition"
  13879. }, AST_Lambda);
  13880. /* -----[ JUMPS ]----- */
  13881. var AST_Jump = DEFNODE("Jump", null, {
  13882. $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
  13883. }, AST_Statement);
  13884. var AST_Exit = DEFNODE("Exit", "value", {
  13885. $documentation: "Base class for “exits” (`return` and `throw`)",
  13886. $propdoc: {
  13887. value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
  13888. },
  13889. _walk: function(visitor) {
  13890. return visitor._visit(this, this.value && function(){
  13891. this.value._walk(visitor);
  13892. });
  13893. }
  13894. }, AST_Jump);
  13895. var AST_Return = DEFNODE("Return", null, {
  13896. $documentation: "A `return` statement"
  13897. }, AST_Exit);
  13898. var AST_Throw = DEFNODE("Throw", null, {
  13899. $documentation: "A `throw` statement"
  13900. }, AST_Exit);
  13901. var AST_LoopControl = DEFNODE("LoopControl", "label", {
  13902. $documentation: "Base class for loop control statements (`break` and `continue`)",
  13903. $propdoc: {
  13904. label: "[AST_LabelRef?] the label, or null if none",
  13905. },
  13906. _walk: function(visitor) {
  13907. return visitor._visit(this, this.label && function(){
  13908. this.label._walk(visitor);
  13909. });
  13910. }
  13911. }, AST_Jump);
  13912. var AST_Break = DEFNODE("Break", null, {
  13913. $documentation: "A `break` statement"
  13914. }, AST_LoopControl);
  13915. var AST_Continue = DEFNODE("Continue", null, {
  13916. $documentation: "A `continue` statement"
  13917. }, AST_LoopControl);
  13918. /* -----[ IF ]----- */
  13919. var AST_If = DEFNODE("If", "condition alternative", {
  13920. $documentation: "A `if` statement",
  13921. $propdoc: {
  13922. condition: "[AST_Node] the `if` condition",
  13923. alternative: "[AST_Statement?] the `else` part, or null if not present"
  13924. },
  13925. _walk: function(visitor) {
  13926. return visitor._visit(this, function(){
  13927. this.condition._walk(visitor);
  13928. this.body._walk(visitor);
  13929. if (this.alternative) this.alternative._walk(visitor);
  13930. });
  13931. }
  13932. }, AST_StatementWithBody);
  13933. /* -----[ SWITCH ]----- */
  13934. var AST_Switch = DEFNODE("Switch", "expression", {
  13935. $documentation: "A `switch` statement",
  13936. $propdoc: {
  13937. expression: "[AST_Node] the `switch` “discriminant”"
  13938. },
  13939. _walk: function(visitor) {
  13940. return visitor._visit(this, function(){
  13941. this.expression._walk(visitor);
  13942. walk_body(this, visitor);
  13943. });
  13944. }
  13945. }, AST_Block);
  13946. var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
  13947. $documentation: "Base class for `switch` branches",
  13948. }, AST_Block);
  13949. var AST_Default = DEFNODE("Default", null, {
  13950. $documentation: "A `default` switch branch",
  13951. }, AST_SwitchBranch);
  13952. var AST_Case = DEFNODE("Case", "expression", {
  13953. $documentation: "A `case` switch branch",
  13954. $propdoc: {
  13955. expression: "[AST_Node] the `case` expression"
  13956. },
  13957. _walk: function(visitor) {
  13958. return visitor._visit(this, function(){
  13959. this.expression._walk(visitor);
  13960. walk_body(this, visitor);
  13961. });
  13962. }
  13963. }, AST_SwitchBranch);
  13964. /* -----[ EXCEPTIONS ]----- */
  13965. var AST_Try = DEFNODE("Try", "bcatch bfinally", {
  13966. $documentation: "A `try` statement",
  13967. $propdoc: {
  13968. bcatch: "[AST_Catch?] the catch block, or null if not present",
  13969. bfinally: "[AST_Finally?] the finally block, or null if not present"
  13970. },
  13971. _walk: function(visitor) {
  13972. return visitor._visit(this, function(){
  13973. walk_body(this, visitor);
  13974. if (this.bcatch) this.bcatch._walk(visitor);
  13975. if (this.bfinally) this.bfinally._walk(visitor);
  13976. });
  13977. }
  13978. }, AST_Block);
  13979. // XXX: this is wrong according to ECMA-262 (12.4). the catch block
  13980. // should introduce another scope, as the argname should be visible
  13981. // only inside the catch block. However, doing it this way because of
  13982. // IE which simply introduces the name in the surrounding scope. If
  13983. // we ever want to fix this then AST_Catch should inherit from
  13984. // AST_Scope.
  13985. var AST_Catch = DEFNODE("Catch", "argname", {
  13986. $documentation: "A `catch` node; only makes sense as part of a `try` statement",
  13987. $propdoc: {
  13988. argname: "[AST_SymbolCatch] symbol for the exception"
  13989. },
  13990. _walk: function(visitor) {
  13991. return visitor._visit(this, function(){
  13992. this.argname._walk(visitor);
  13993. walk_body(this, visitor);
  13994. });
  13995. }
  13996. }, AST_Block);
  13997. var AST_Finally = DEFNODE("Finally", null, {
  13998. $documentation: "A `finally` node; only makes sense as part of a `try` statement"
  13999. }, AST_Block);
  14000. /* -----[ VAR/CONST ]----- */
  14001. var AST_Definitions = DEFNODE("Definitions", "definitions", {
  14002. $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
  14003. $propdoc: {
  14004. definitions: "[AST_VarDef*] array of variable definitions"
  14005. },
  14006. _walk: function(visitor) {
  14007. return visitor._visit(this, function(){
  14008. this.definitions.forEach(function(def){
  14009. def._walk(visitor);
  14010. });
  14011. });
  14012. }
  14013. }, AST_Statement);
  14014. var AST_Var = DEFNODE("Var", null, {
  14015. $documentation: "A `var` statement"
  14016. }, AST_Definitions);
  14017. var AST_Const = DEFNODE("Const", null, {
  14018. $documentation: "A `const` statement"
  14019. }, AST_Definitions);
  14020. var AST_VarDef = DEFNODE("VarDef", "name value", {
  14021. $documentation: "A variable declaration; only appears in a AST_Definitions node",
  14022. $propdoc: {
  14023. name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
  14024. value: "[AST_Node?] initializer, or null of there's no initializer"
  14025. },
  14026. _walk: function(visitor) {
  14027. return visitor._visit(this, function(){
  14028. this.name._walk(visitor);
  14029. if (this.value) this.value._walk(visitor);
  14030. });
  14031. }
  14032. });
  14033. /* -----[ OTHER ]----- */
  14034. var AST_Call = DEFNODE("Call", "expression args", {
  14035. $documentation: "A function call expression",
  14036. $propdoc: {
  14037. expression: "[AST_Node] expression to invoke as function",
  14038. args: "[AST_Node*] array of arguments"
  14039. },
  14040. _walk: function(visitor) {
  14041. return visitor._visit(this, function(){
  14042. this.expression._walk(visitor);
  14043. this.args.forEach(function(arg){
  14044. arg._walk(visitor);
  14045. });
  14046. });
  14047. }
  14048. });
  14049. var AST_New = DEFNODE("New", null, {
  14050. $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
  14051. }, AST_Call);
  14052. var AST_Seq = DEFNODE("Seq", "car cdr", {
  14053. $documentation: "A sequence expression (two comma-separated expressions)",
  14054. $propdoc: {
  14055. car: "[AST_Node] first element in sequence",
  14056. cdr: "[AST_Node] second element in sequence"
  14057. },
  14058. $cons: function(x, y) {
  14059. var seq = new AST_Seq(x);
  14060. seq.car = x;
  14061. seq.cdr = y;
  14062. return seq;
  14063. },
  14064. $from_array: function(array) {
  14065. if (array.length == 0) return null;
  14066. if (array.length == 1) return array[0].clone();
  14067. var list = null;
  14068. for (var i = array.length; --i >= 0;) {
  14069. list = AST_Seq.cons(array[i], list);
  14070. }
  14071. var p = list;
  14072. while (p) {
  14073. if (p.cdr && !p.cdr.cdr) {
  14074. p.cdr = p.cdr.car;
  14075. break;
  14076. }
  14077. p = p.cdr;
  14078. }
  14079. return list;
  14080. },
  14081. to_array: function() {
  14082. var p = this, a = [];
  14083. while (p) {
  14084. a.push(p.car);
  14085. if (p.cdr && !(p.cdr instanceof AST_Seq)) {
  14086. a.push(p.cdr);
  14087. break;
  14088. }
  14089. p = p.cdr;
  14090. }
  14091. return a;
  14092. },
  14093. add: function(node) {
  14094. var p = this;
  14095. while (p) {
  14096. if (!(p.cdr instanceof AST_Seq)) {
  14097. var cell = AST_Seq.cons(p.cdr, node);
  14098. return p.cdr = cell;
  14099. }
  14100. p = p.cdr;
  14101. }
  14102. },
  14103. _walk: function(visitor) {
  14104. return visitor._visit(this, function(){
  14105. this.car._walk(visitor);
  14106. if (this.cdr) this.cdr._walk(visitor);
  14107. });
  14108. }
  14109. });
  14110. var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
  14111. $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
  14112. $propdoc: {
  14113. expression: "[AST_Node] the “container” expression",
  14114. property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
  14115. }
  14116. });
  14117. var AST_Dot = DEFNODE("Dot", null, {
  14118. $documentation: "A dotted property access expression",
  14119. _walk: function(visitor) {
  14120. return visitor._visit(this, function(){
  14121. this.expression._walk(visitor);
  14122. });
  14123. }
  14124. }, AST_PropAccess);
  14125. var AST_Sub = DEFNODE("Sub", null, {
  14126. $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
  14127. _walk: function(visitor) {
  14128. return visitor._visit(this, function(){
  14129. this.expression._walk(visitor);
  14130. this.property._walk(visitor);
  14131. });
  14132. }
  14133. }, AST_PropAccess);
  14134. var AST_Unary = DEFNODE("Unary", "operator expression", {
  14135. $documentation: "Base class for unary expressions",
  14136. $propdoc: {
  14137. operator: "[string] the operator",
  14138. expression: "[AST_Node] expression that this unary operator applies to"
  14139. },
  14140. _walk: function(visitor) {
  14141. return visitor._visit(this, function(){
  14142. this.expression._walk(visitor);
  14143. });
  14144. }
  14145. });
  14146. var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
  14147. $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
  14148. }, AST_Unary);
  14149. var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
  14150. $documentation: "Unary postfix expression, i.e. `i++`"
  14151. }, AST_Unary);
  14152. var AST_Binary = DEFNODE("Binary", "left operator right", {
  14153. $documentation: "Binary expression, i.e. `a + b`",
  14154. $propdoc: {
  14155. left: "[AST_Node] left-hand side expression",
  14156. operator: "[string] the operator",
  14157. right: "[AST_Node] right-hand side expression"
  14158. },
  14159. _walk: function(visitor) {
  14160. return visitor._visit(this, function(){
  14161. this.left._walk(visitor);
  14162. this.right._walk(visitor);
  14163. });
  14164. }
  14165. });
  14166. var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
  14167. $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
  14168. $propdoc: {
  14169. condition: "[AST_Node]",
  14170. consequent: "[AST_Node]",
  14171. alternative: "[AST_Node]"
  14172. },
  14173. _walk: function(visitor) {
  14174. return visitor._visit(this, function(){
  14175. this.condition._walk(visitor);
  14176. this.consequent._walk(visitor);
  14177. this.alternative._walk(visitor);
  14178. });
  14179. }
  14180. });
  14181. var AST_Assign = DEFNODE("Assign", null, {
  14182. $documentation: "An assignment expression — `a = b + 5`",
  14183. }, AST_Binary);
  14184. /* -----[ LITERALS ]----- */
  14185. var AST_Array = DEFNODE("Array", "elements", {
  14186. $documentation: "An array literal",
  14187. $propdoc: {
  14188. elements: "[AST_Node*] array of elements"
  14189. },
  14190. _walk: function(visitor) {
  14191. return visitor._visit(this, function(){
  14192. this.elements.forEach(function(el){
  14193. el._walk(visitor);
  14194. });
  14195. });
  14196. }
  14197. });
  14198. var AST_Object = DEFNODE("Object", "properties", {
  14199. $documentation: "An object literal",
  14200. $propdoc: {
  14201. properties: "[AST_ObjectProperty*] array of properties"
  14202. },
  14203. _walk: function(visitor) {
  14204. return visitor._visit(this, function(){
  14205. this.properties.forEach(function(prop){
  14206. prop._walk(visitor);
  14207. });
  14208. });
  14209. }
  14210. });
  14211. var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
  14212. $documentation: "Base class for literal object properties",
  14213. $propdoc: {
  14214. key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code",
  14215. value: "[AST_Node] property value. For setters and getters this is an AST_Function."
  14216. },
  14217. _walk: function(visitor) {
  14218. return visitor._visit(this, function(){
  14219. this.value._walk(visitor);
  14220. });
  14221. }
  14222. });
  14223. var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
  14224. $documentation: "A key: value object property",
  14225. }, AST_ObjectProperty);
  14226. var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
  14227. $documentation: "An object setter property",
  14228. }, AST_ObjectProperty);
  14229. var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
  14230. $documentation: "An object getter property",
  14231. }, AST_ObjectProperty);
  14232. var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
  14233. $propdoc: {
  14234. name: "[string] name of this symbol",
  14235. scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
  14236. thedef: "[SymbolDef/S] the definition of this symbol"
  14237. },
  14238. $documentation: "Base class for all symbols",
  14239. });
  14240. var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
  14241. $documentation: "The name of a property accessor (setter/getter function)"
  14242. }, AST_Symbol);
  14243. var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
  14244. $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
  14245. $propdoc: {
  14246. init: "[AST_Node*/S] array of initializers for this declaration."
  14247. }
  14248. }, AST_Symbol);
  14249. var AST_SymbolVar = DEFNODE("SymbolVar", null, {
  14250. $documentation: "Symbol defining a variable",
  14251. }, AST_SymbolDeclaration);
  14252. var AST_SymbolConst = DEFNODE("SymbolConst", null, {
  14253. $documentation: "A constant declaration"
  14254. }, AST_SymbolDeclaration);
  14255. var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
  14256. $documentation: "Symbol naming a function argument",
  14257. }, AST_SymbolVar);
  14258. var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
  14259. $documentation: "Symbol defining a function",
  14260. }, AST_SymbolDeclaration);
  14261. var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
  14262. $documentation: "Symbol naming a function expression",
  14263. }, AST_SymbolDeclaration);
  14264. var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
  14265. $documentation: "Symbol naming the exception in catch",
  14266. }, AST_SymbolDeclaration);
  14267. var AST_Label = DEFNODE("Label", "references", {
  14268. $documentation: "Symbol naming a label (declaration)",
  14269. $propdoc: {
  14270. references: "[AST_LabelRef*] a list of nodes referring to this label"
  14271. }
  14272. }, AST_Symbol);
  14273. var AST_SymbolRef = DEFNODE("SymbolRef", null, {
  14274. $documentation: "Reference to some symbol (not definition/declaration)",
  14275. }, AST_Symbol);
  14276. var AST_LabelRef = DEFNODE("LabelRef", null, {
  14277. $documentation: "Reference to a label symbol",
  14278. }, AST_Symbol);
  14279. var AST_This = DEFNODE("This", null, {
  14280. $documentation: "The `this` symbol",
  14281. }, AST_Symbol);
  14282. var AST_Constant = DEFNODE("Constant", null, {
  14283. $documentation: "Base class for all constants",
  14284. getValue: function() {
  14285. return this.value;
  14286. }
  14287. });
  14288. var AST_String = DEFNODE("String", "value", {
  14289. $documentation: "A string literal",
  14290. $propdoc: {
  14291. value: "[string] the contents of this string"
  14292. }
  14293. }, AST_Constant);
  14294. var AST_Number = DEFNODE("Number", "value", {
  14295. $documentation: "A number literal",
  14296. $propdoc: {
  14297. value: "[number] the numeric value"
  14298. }
  14299. }, AST_Constant);
  14300. var AST_RegExp = DEFNODE("RegExp", "value", {
  14301. $documentation: "A regexp literal",
  14302. $propdoc: {
  14303. value: "[RegExp] the actual regexp"
  14304. }
  14305. }, AST_Constant);
  14306. var AST_Atom = DEFNODE("Atom", null, {
  14307. $documentation: "Base class for atoms",
  14308. }, AST_Constant);
  14309. var AST_Null = DEFNODE("Null", null, {
  14310. $documentation: "The `null` atom",
  14311. value: null
  14312. }, AST_Atom);
  14313. var AST_NaN = DEFNODE("NaN", null, {
  14314. $documentation: "The impossible value",
  14315. value: 0/0
  14316. }, AST_Atom);
  14317. var AST_Undefined = DEFNODE("Undefined", null, {
  14318. $documentation: "The `undefined` value",
  14319. value: (function(){}())
  14320. }, AST_Atom);
  14321. var AST_Hole = DEFNODE("Hole", null, {
  14322. $documentation: "A hole in an array",
  14323. value: (function(){}())
  14324. }, AST_Atom);
  14325. var AST_Infinity = DEFNODE("Infinity", null, {
  14326. $documentation: "The `Infinity` value",
  14327. value: 1/0
  14328. }, AST_Atom);
  14329. var AST_Boolean = DEFNODE("Boolean", null, {
  14330. $documentation: "Base class for booleans",
  14331. }, AST_Atom);
  14332. var AST_False = DEFNODE("False", null, {
  14333. $documentation: "The `false` atom",
  14334. value: false
  14335. }, AST_Boolean);
  14336. var AST_True = DEFNODE("True", null, {
  14337. $documentation: "The `true` atom",
  14338. value: true
  14339. }, AST_Boolean);
  14340. /* -----[ TreeWalker ]----- */
  14341. function TreeWalker(callback) {
  14342. this.visit = callback;
  14343. this.stack = [];
  14344. };
  14345. TreeWalker.prototype = {
  14346. _visit: function(node, descend) {
  14347. this.stack.push(node);
  14348. var ret = this.visit(node, descend ? function(){
  14349. descend.call(node);
  14350. } : noop);
  14351. if (!ret && descend) {
  14352. descend.call(node);
  14353. }
  14354. this.stack.pop();
  14355. return ret;
  14356. },
  14357. parent: function(n) {
  14358. return this.stack[this.stack.length - 2 - (n || 0)];
  14359. },
  14360. push: function (node) {
  14361. this.stack.push(node);
  14362. },
  14363. pop: function() {
  14364. return this.stack.pop();
  14365. },
  14366. self: function() {
  14367. return this.stack[this.stack.length - 1];
  14368. },
  14369. find_parent: function(type) {
  14370. var stack = this.stack;
  14371. for (var i = stack.length; --i >= 0;) {
  14372. var x = stack[i];
  14373. if (x instanceof type) return x;
  14374. }
  14375. },
  14376. has_directive: function(type) {
  14377. return this.find_parent(AST_Scope).has_directive(type);
  14378. },
  14379. in_boolean_context: function() {
  14380. var stack = this.stack;
  14381. var i = stack.length, self = stack[--i];
  14382. while (i > 0) {
  14383. var p = stack[--i];
  14384. if ((p instanceof AST_If && p.condition === self) ||
  14385. (p instanceof AST_Conditional && p.condition === self) ||
  14386. (p instanceof AST_DWLoop && p.condition === self) ||
  14387. (p instanceof AST_For && p.condition === self) ||
  14388. (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
  14389. {
  14390. return true;
  14391. }
  14392. if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
  14393. return false;
  14394. self = p;
  14395. }
  14396. },
  14397. loopcontrol_target: function(label) {
  14398. var stack = this.stack;
  14399. if (label) {
  14400. for (var i = stack.length; --i >= 0;) {
  14401. var x = stack[i];
  14402. if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
  14403. return x.body;
  14404. }
  14405. }
  14406. } else {
  14407. for (var i = stack.length; --i >= 0;) {
  14408. var x = stack[i];
  14409. if (x instanceof AST_Switch
  14410. || x instanceof AST_For
  14411. || x instanceof AST_ForIn
  14412. || x instanceof AST_DWLoop) return x;
  14413. }
  14414. }
  14415. }
  14416. };
  14417. /***********************************************************************
  14418. A JavaScript tokenizer / parser / beautifier / compressor.
  14419. https://github.com/mishoo/UglifyJS2
  14420. -------------------------------- (C) ---------------------------------
  14421. Author: Mihai Bazon
  14422. <mihai.bazon@gmail.com>
  14423. http://mihai.bazon.net/blog
  14424. Distributed under the BSD license:
  14425. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  14426. Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
  14427. Redistribution and use in source and binary forms, with or without
  14428. modification, are permitted provided that the following conditions
  14429. are met:
  14430. * Redistributions of source code must retain the above
  14431. copyright notice, this list of conditions and the following
  14432. disclaimer.
  14433. * Redistributions in binary form must reproduce the above
  14434. copyright notice, this list of conditions and the following
  14435. disclaimer in the documentation and/or other materials
  14436. provided with the distribution.
  14437. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  14438. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  14439. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  14440. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  14441. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  14442. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  14443. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  14444. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  14445. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  14446. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  14447. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  14448. SUCH DAMAGE.
  14449. ***********************************************************************/
  14450. "use strict";
  14451. var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
  14452. var KEYWORDS_ATOM = 'false null true';
  14453. var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile'
  14454. + " " + KEYWORDS_ATOM + " " + KEYWORDS;
  14455. var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
  14456. KEYWORDS = makePredicate(KEYWORDS);
  14457. RESERVED_WORDS = makePredicate(RESERVED_WORDS);
  14458. KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
  14459. KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
  14460. var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
  14461. var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
  14462. var RE_OCT_NUMBER = /^0[0-7]+$/;
  14463. var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
  14464. var OPERATORS = makePredicate([
  14465. "in",
  14466. "instanceof",
  14467. "typeof",
  14468. "new",
  14469. "void",
  14470. "delete",
  14471. "++",
  14472. "--",
  14473. "+",
  14474. "-",
  14475. "!",
  14476. "~",
  14477. "&",
  14478. "|",
  14479. "^",
  14480. "*",
  14481. "/",
  14482. "%",
  14483. ">>",
  14484. "<<",
  14485. ">>>",
  14486. "<",
  14487. ">",
  14488. "<=",
  14489. ">=",
  14490. "==",
  14491. "===",
  14492. "!=",
  14493. "!==",
  14494. "?",
  14495. "=",
  14496. "+=",
  14497. "-=",
  14498. "/=",
  14499. "*=",
  14500. "%=",
  14501. ">>=",
  14502. "<<=",
  14503. ">>>=",
  14504. "|=",
  14505. "^=",
  14506. "&=",
  14507. "&&",
  14508. "||"
  14509. ]);
  14510. var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
  14511. var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
  14512. var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
  14513. var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
  14514. /* -----[ Tokenizer ]----- */
  14515. // regexps adapted from http://xregexp.com/plugins/#unicode
  14516. var UNICODE = {
  14517. letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\
  14518. non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
  14519. space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
  14520. connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
  14521. };
  14522. function is_letter(code) {
  14523. return (code >= 97 && code <= 122)
  14524. || (code >= 65 && code <= 90)
  14525. || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
  14526. };
  14527. function is_digit(code) {
  14528. return code >= 48 && code <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
  14529. };
  14530. function is_alphanumeric_char(code) {
  14531. return is_digit(code) || is_letter(code);
  14532. };
  14533. function is_unicode_combining_mark(ch) {
  14534. return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
  14535. };
  14536. function is_unicode_connector_punctuation(ch) {
  14537. return UNICODE.connector_punctuation.test(ch);
  14538. };
  14539. function is_identifier(name) {
  14540. return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
  14541. };
  14542. function is_identifier_start(code) {
  14543. return code == 36 || code == 95 || is_letter(code);
  14544. };
  14545. function is_identifier_char(ch) {
  14546. var code = ch.charCodeAt(0);
  14547. return is_identifier_start(code)
  14548. || is_digit(code)
  14549. || code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
  14550. || code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
  14551. || is_unicode_combining_mark(ch)
  14552. || is_unicode_connector_punctuation(ch)
  14553. ;
  14554. };
  14555. function is_identifier_string(str){
  14556. var i = str.length;
  14557. if (i == 0) return false;
  14558. if (is_digit(str.charCodeAt(0))) return false;
  14559. while (--i >= 0) {
  14560. if (!is_identifier_char(str.charAt(i)))
  14561. return false;
  14562. }
  14563. return true;
  14564. };
  14565. function parse_js_number(num) {
  14566. if (RE_HEX_NUMBER.test(num)) {
  14567. return parseInt(num.substr(2), 16);
  14568. } else if (RE_OCT_NUMBER.test(num)) {
  14569. return parseInt(num.substr(1), 8);
  14570. } else if (RE_DEC_NUMBER.test(num)) {
  14571. return parseFloat(num);
  14572. }
  14573. };
  14574. function JS_Parse_Error(message, line, col, pos) {
  14575. this.message = message;
  14576. this.line = line;
  14577. this.col = col;
  14578. this.pos = pos;
  14579. this.stack = new Error().stack;
  14580. };
  14581. JS_Parse_Error.prototype.toString = function() {
  14582. return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
  14583. };
  14584. function js_error(message, filename, line, col, pos) {
  14585. throw new JS_Parse_Error(message, line, col, pos);
  14586. };
  14587. function is_token(token, type, val) {
  14588. return token.type == type && (val == null || token.value == val);
  14589. };
  14590. var EX_EOF = {};
  14591. function tokenizer($TEXT, filename) {
  14592. var S = {
  14593. text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''),
  14594. filename : filename,
  14595. pos : 0,
  14596. tokpos : 0,
  14597. line : 1,
  14598. tokline : 0,
  14599. col : 0,
  14600. tokcol : 0,
  14601. newline_before : false,
  14602. regex_allowed : false,
  14603. comments_before : []
  14604. };
  14605. function peek() { return S.text.charAt(S.pos); };
  14606. function next(signal_eof, in_string) {
  14607. var ch = S.text.charAt(S.pos++);
  14608. if (signal_eof && !ch)
  14609. throw EX_EOF;
  14610. if (ch == "\n") {
  14611. S.newline_before = S.newline_before || !in_string;
  14612. ++S.line;
  14613. S.col = 0;
  14614. } else {
  14615. ++S.col;
  14616. }
  14617. return ch;
  14618. };
  14619. function find(what, signal_eof) {
  14620. var pos = S.text.indexOf(what, S.pos);
  14621. if (signal_eof && pos == -1) throw EX_EOF;
  14622. return pos;
  14623. };
  14624. function start_token() {
  14625. S.tokline = S.line;
  14626. S.tokcol = S.col;
  14627. S.tokpos = S.pos;
  14628. };
  14629. function token(type, value, is_comment) {
  14630. S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
  14631. (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
  14632. (type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
  14633. var ret = {
  14634. type : type,
  14635. value : value,
  14636. line : S.tokline,
  14637. col : S.tokcol,
  14638. pos : S.tokpos,
  14639. endpos : S.pos,
  14640. nlb : S.newline_before,
  14641. file : filename
  14642. };
  14643. if (!is_comment) {
  14644. ret.comments_before = S.comments_before;
  14645. S.comments_before = [];
  14646. // make note of any newlines in the comments that came before
  14647. for (var i = 0, len = ret.comments_before.length; i < len; i++) {
  14648. ret.nlb = ret.nlb || ret.comments_before[i].nlb;
  14649. }
  14650. }
  14651. S.newline_before = false;
  14652. return new AST_Token(ret);
  14653. };
  14654. function skip_whitespace() {
  14655. while (WHITESPACE_CHARS(peek()))
  14656. next();
  14657. };
  14658. function read_while(pred) {
  14659. var ret = "", ch, i = 0;
  14660. while ((ch = peek()) && pred(ch, i++))
  14661. ret += next();
  14662. return ret;
  14663. };
  14664. function parse_error(err) {
  14665. js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
  14666. };
  14667. function read_num(prefix) {
  14668. var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
  14669. var num = read_while(function(ch, i){
  14670. var code = ch.charCodeAt(0);
  14671. switch (code) {
  14672. case 120: case 88: // xX
  14673. return has_x ? false : (has_x = true);
  14674. case 101: case 69: // eE
  14675. return has_x ? true : has_e ? false : (has_e = after_e = true);
  14676. case 45: // -
  14677. return after_e || (i == 0 && !prefix);
  14678. case 43: // +
  14679. return after_e;
  14680. case (after_e = false, 46): // .
  14681. return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
  14682. }
  14683. return is_alphanumeric_char(code);
  14684. });
  14685. if (prefix) num = prefix + num;
  14686. var valid = parse_js_number(num);
  14687. if (!isNaN(valid)) {
  14688. return token("num", valid);
  14689. } else {
  14690. parse_error("Invalid syntax: " + num);
  14691. }
  14692. };
  14693. function read_escaped_char(in_string) {
  14694. var ch = next(true, in_string);
  14695. switch (ch.charCodeAt(0)) {
  14696. case 110 : return "\n";
  14697. case 114 : return "\r";
  14698. case 116 : return "\t";
  14699. case 98 : return "\b";
  14700. case 118 : return "\u000b"; // \v
  14701. case 102 : return "\f";
  14702. case 48 : return "\0";
  14703. case 120 : return String.fromCharCode(hex_bytes(2)); // \x
  14704. case 117 : return String.fromCharCode(hex_bytes(4)); // \u
  14705. case 10 : return ""; // newline
  14706. default : return ch;
  14707. }
  14708. };
  14709. function hex_bytes(n) {
  14710. var num = 0;
  14711. for (; n > 0; --n) {
  14712. var digit = parseInt(next(true), 16);
  14713. if (isNaN(digit))
  14714. parse_error("Invalid hex-character pattern in string");
  14715. num = (num << 4) | digit;
  14716. }
  14717. return num;
  14718. };
  14719. var read_string = with_eof_error("Unterminated string constant", function(){
  14720. var quote = next(), ret = "";
  14721. for (;;) {
  14722. var ch = next(true);
  14723. if (ch == "\\") {
  14724. // read OctalEscapeSequence (XXX: deprecated if "strict mode")
  14725. // https://github.com/mishoo/UglifyJS/issues/178
  14726. var octal_len = 0, first = null;
  14727. ch = read_while(function(ch){
  14728. if (ch >= "0" && ch <= "7") {
  14729. if (!first) {
  14730. first = ch;
  14731. return ++octal_len;
  14732. }
  14733. else if (first <= "3" && octal_len <= 2) return ++octal_len;
  14734. else if (first >= "4" && octal_len <= 1) return ++octal_len;
  14735. }
  14736. return false;
  14737. });
  14738. if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
  14739. else ch = read_escaped_char(true);
  14740. }
  14741. else if (ch == quote) break;
  14742. ret += ch;
  14743. }
  14744. return token("string", ret);
  14745. });
  14746. function read_line_comment() {
  14747. next();
  14748. var i = find("\n"), ret;
  14749. if (i == -1) {
  14750. ret = S.text.substr(S.pos);
  14751. S.pos = S.text.length;
  14752. } else {
  14753. ret = S.text.substring(S.pos, i);
  14754. S.pos = i;
  14755. }
  14756. return token("comment1", ret, true);
  14757. };
  14758. var read_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
  14759. next();
  14760. var i = find("*/", true);
  14761. var text = S.text.substring(S.pos, i);
  14762. var a = text.split("\n"), n = a.length;
  14763. // update stream position
  14764. S.pos = i + 2;
  14765. S.line += n - 1;
  14766. if (n > 1) S.col = a[n - 1].length;
  14767. else S.col += a[n - 1].length;
  14768. S.col += 2;
  14769. S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
  14770. return token("comment2", text, true);
  14771. });
  14772. function read_name() {
  14773. var backslash = false, name = "", ch, escaped = false, hex;
  14774. while ((ch = peek()) != null) {
  14775. if (!backslash) {
  14776. if (ch == "\\") escaped = backslash = true, next();
  14777. else if (is_identifier_char(ch)) name += next();
  14778. else break;
  14779. }
  14780. else {
  14781. if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
  14782. ch = read_escaped_char();
  14783. if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
  14784. name += ch;
  14785. backslash = false;
  14786. }
  14787. }
  14788. if (KEYWORDS(name) && escaped) {
  14789. hex = name.charCodeAt(0).toString(16).toUpperCase();
  14790. name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
  14791. }
  14792. return name;
  14793. };
  14794. var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
  14795. var prev_backslash = false, ch, in_class = false;
  14796. while ((ch = next(true))) if (prev_backslash) {
  14797. regexp += "\\" + ch;
  14798. prev_backslash = false;
  14799. } else if (ch == "[") {
  14800. in_class = true;
  14801. regexp += ch;
  14802. } else if (ch == "]" && in_class) {
  14803. in_class = false;
  14804. regexp += ch;
  14805. } else if (ch == "/" && !in_class) {
  14806. break;
  14807. } else if (ch == "\\") {
  14808. prev_backslash = true;
  14809. } else {
  14810. regexp += ch;
  14811. }
  14812. var mods = read_name();
  14813. return token("regexp", new RegExp(regexp, mods));
  14814. });
  14815. function read_operator(prefix) {
  14816. function grow(op) {
  14817. if (!peek()) return op;
  14818. var bigger = op + peek();
  14819. if (OPERATORS(bigger)) {
  14820. next();
  14821. return grow(bigger);
  14822. } else {
  14823. return op;
  14824. }
  14825. };
  14826. return token("operator", grow(prefix || next()));
  14827. };
  14828. function handle_slash() {
  14829. next();
  14830. var regex_allowed = S.regex_allowed;
  14831. switch (peek()) {
  14832. case "/":
  14833. S.comments_before.push(read_line_comment());
  14834. S.regex_allowed = regex_allowed;
  14835. return next_token();
  14836. case "*":
  14837. S.comments_before.push(read_multiline_comment());
  14838. S.regex_allowed = regex_allowed;
  14839. return next_token();
  14840. }
  14841. return S.regex_allowed ? read_regexp("") : read_operator("/");
  14842. };
  14843. function handle_dot() {
  14844. next();
  14845. return is_digit(peek().charCodeAt(0))
  14846. ? read_num(".")
  14847. : token("punc", ".");
  14848. };
  14849. function read_word() {
  14850. var word = read_name();
  14851. return KEYWORDS_ATOM(word) ? token("atom", word)
  14852. : !KEYWORDS(word) ? token("name", word)
  14853. : OPERATORS(word) ? token("operator", word)
  14854. : token("keyword", word);
  14855. };
  14856. function with_eof_error(eof_error, cont) {
  14857. return function(x) {
  14858. try {
  14859. return cont(x);
  14860. } catch(ex) {
  14861. if (ex === EX_EOF) parse_error(eof_error);
  14862. else throw ex;
  14863. }
  14864. };
  14865. };
  14866. function next_token(force_regexp) {
  14867. if (force_regexp != null)
  14868. return read_regexp(force_regexp);
  14869. skip_whitespace();
  14870. start_token();
  14871. var ch = peek();
  14872. if (!ch) return token("eof");
  14873. var code = ch.charCodeAt(0);
  14874. switch (code) {
  14875. case 34: case 39: return read_string();
  14876. case 46: return handle_dot();
  14877. case 47: return handle_slash();
  14878. }
  14879. if (is_digit(code)) return read_num();
  14880. if (PUNC_CHARS(ch)) return token("punc", next());
  14881. if (OPERATOR_CHARS(ch)) return read_operator();
  14882. if (code == 92 || is_identifier_start(code)) return read_word();
  14883. parse_error("Unexpected character '" + ch + "'");
  14884. };
  14885. next_token.context = function(nc) {
  14886. if (nc) S = nc;
  14887. return S;
  14888. };
  14889. return next_token;
  14890. };
  14891. /* -----[ Parser (constants) ]----- */
  14892. var UNARY_PREFIX = makePredicate([
  14893. "typeof",
  14894. "void",
  14895. "delete",
  14896. "--",
  14897. "++",
  14898. "!",
  14899. "~",
  14900. "-",
  14901. "+"
  14902. ]);
  14903. var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
  14904. var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
  14905. var PRECEDENCE = (function(a, ret){
  14906. for (var i = 0, n = 1; i < a.length; ++i, ++n) {
  14907. var b = a[i];
  14908. for (var j = 0; j < b.length; ++j) {
  14909. ret[b[j]] = n;
  14910. }
  14911. }
  14912. return ret;
  14913. })(
  14914. [
  14915. ["||"],
  14916. ["&&"],
  14917. ["|"],
  14918. ["^"],
  14919. ["&"],
  14920. ["==", "===", "!=", "!=="],
  14921. ["<", ">", "<=", ">=", "in", "instanceof"],
  14922. [">>", "<<", ">>>"],
  14923. ["+", "-"],
  14924. ["*", "/", "%"]
  14925. ],
  14926. {}
  14927. );
  14928. var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
  14929. var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
  14930. /* -----[ Parser ]----- */
  14931. function parse($TEXT, options) {
  14932. options = defaults(options, {
  14933. strict : false,
  14934. filename : null,
  14935. toplevel : null,
  14936. expression : false
  14937. });
  14938. var S = {
  14939. input : typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT,
  14940. token : null,
  14941. prev : null,
  14942. peeked : null,
  14943. in_function : 0,
  14944. in_directives : true,
  14945. in_loop : 0,
  14946. labels : []
  14947. };
  14948. S.token = next();
  14949. function is(type, value) {
  14950. return is_token(S.token, type, value);
  14951. };
  14952. function peek() { return S.peeked || (S.peeked = S.input()); };
  14953. function next() {
  14954. S.prev = S.token;
  14955. if (S.peeked) {
  14956. S.token = S.peeked;
  14957. S.peeked = null;
  14958. } else {
  14959. S.token = S.input();
  14960. }
  14961. S.in_directives = S.in_directives && (
  14962. S.token.type == "string" || is("punc", ";")
  14963. );
  14964. return S.token;
  14965. };
  14966. function prev() {
  14967. return S.prev;
  14968. };
  14969. function croak(msg, line, col, pos) {
  14970. var ctx = S.input.context();
  14971. js_error(msg,
  14972. ctx.filename,
  14973. line != null ? line : ctx.tokline,
  14974. col != null ? col : ctx.tokcol,
  14975. pos != null ? pos : ctx.tokpos);
  14976. };
  14977. function token_error(token, msg) {
  14978. croak(msg, token.line, token.col);
  14979. };
  14980. function unexpected(token) {
  14981. if (token == null)
  14982. token = S.token;
  14983. token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
  14984. };
  14985. function expect_token(type, val) {
  14986. if (is(type, val)) {
  14987. return next();
  14988. }
  14989. token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
  14990. };
  14991. function expect(punc) { return expect_token("punc", punc); };
  14992. function can_insert_semicolon() {
  14993. return !options.strict && (
  14994. S.token.nlb || is("eof") || is("punc", "}")
  14995. );
  14996. };
  14997. function semicolon() {
  14998. if (is("punc", ";")) next();
  14999. else if (!can_insert_semicolon()) unexpected();
  15000. };
  15001. function parenthesised() {
  15002. expect("(");
  15003. var exp = expression(true);
  15004. expect(")");
  15005. return exp;
  15006. };
  15007. function embed_tokens(parser) {
  15008. return function() {
  15009. var start = S.token;
  15010. var expr = parser();
  15011. var end = prev();
  15012. expr.start = start;
  15013. expr.end = end;
  15014. return expr;
  15015. };
  15016. };
  15017. var statement = embed_tokens(function() {
  15018. var tmp;
  15019. if (is("operator", "/") || is("operator", "/=")) {
  15020. S.peeked = null;
  15021. S.token = S.input(S.token.value.substr(1)); // force regexp
  15022. }
  15023. switch (S.token.type) {
  15024. case "string":
  15025. var dir = S.in_directives, stat = simple_statement();
  15026. // XXXv2: decide how to fix directives
  15027. if (dir && stat.body instanceof AST_String && !is("punc", ","))
  15028. return new AST_Directive({ value: stat.body.value });
  15029. return stat;
  15030. case "num":
  15031. case "regexp":
  15032. case "operator":
  15033. case "atom":
  15034. return simple_statement();
  15035. case "name":
  15036. return is_token(peek(), "punc", ":")
  15037. ? labeled_statement()
  15038. : simple_statement();
  15039. case "punc":
  15040. switch (S.token.value) {
  15041. case "{":
  15042. return new AST_BlockStatement({
  15043. start : S.token,
  15044. body : block_(),
  15045. end : prev()
  15046. });
  15047. case "[":
  15048. case "(":
  15049. return simple_statement();
  15050. case ";":
  15051. next();
  15052. return new AST_EmptyStatement();
  15053. default:
  15054. unexpected();
  15055. }
  15056. case "keyword":
  15057. switch (tmp = S.token.value, next(), tmp) {
  15058. case "break":
  15059. return break_cont(AST_Break);
  15060. case "continue":
  15061. return break_cont(AST_Continue);
  15062. case "debugger":
  15063. semicolon();
  15064. return new AST_Debugger();
  15065. case "do":
  15066. return new AST_Do({
  15067. body : in_loop(statement),
  15068. condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp)
  15069. });
  15070. case "while":
  15071. return new AST_While({
  15072. condition : parenthesised(),
  15073. body : in_loop(statement)
  15074. });
  15075. case "for":
  15076. return for_();
  15077. case "function":
  15078. return function_(true);
  15079. case "if":
  15080. return if_();
  15081. case "return":
  15082. if (S.in_function == 0)
  15083. croak("'return' outside of function");
  15084. return new AST_Return({
  15085. value: ( is("punc", ";")
  15086. ? (next(), null)
  15087. : can_insert_semicolon()
  15088. ? null
  15089. : (tmp = expression(true), semicolon(), tmp) )
  15090. });
  15091. case "switch":
  15092. return new AST_Switch({
  15093. expression : parenthesised(),
  15094. body : in_loop(switch_body_)
  15095. });
  15096. case "throw":
  15097. if (S.token.nlb)
  15098. croak("Illegal newline after 'throw'");
  15099. return new AST_Throw({
  15100. value: (tmp = expression(true), semicolon(), tmp)
  15101. });
  15102. case "try":
  15103. return try_();
  15104. case "var":
  15105. return tmp = var_(), semicolon(), tmp;
  15106. case "const":
  15107. return tmp = const_(), semicolon(), tmp;
  15108. case "with":
  15109. return new AST_With({
  15110. expression : parenthesised(),
  15111. body : statement()
  15112. });
  15113. default:
  15114. unexpected();
  15115. }
  15116. }
  15117. });
  15118. function labeled_statement() {
  15119. var label = as_symbol(AST_Label);
  15120. if (find_if(function(l){ return l.name == label.name }, S.labels)) {
  15121. // ECMA-262, 12.12: An ECMAScript program is considered
  15122. // syntactically incorrect if it contains a
  15123. // LabelledStatement that is enclosed by a
  15124. // LabelledStatement with the same Identifier as label.
  15125. croak("Label " + label.name + " defined twice");
  15126. }
  15127. expect(":");
  15128. S.labels.push(label);
  15129. var stat = statement();
  15130. S.labels.pop();
  15131. return new AST_LabeledStatement({ body: stat, label: label });
  15132. };
  15133. function simple_statement(tmp) {
  15134. return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
  15135. };
  15136. function break_cont(type) {
  15137. var label = null;
  15138. if (!can_insert_semicolon()) {
  15139. label = as_symbol(AST_LabelRef, true);
  15140. }
  15141. if (label != null) {
  15142. if (!find_if(function(l){ return l.name == label.name }, S.labels))
  15143. croak("Undefined label " + label.name);
  15144. }
  15145. else if (S.in_loop == 0)
  15146. croak(type.TYPE + " not inside a loop or switch");
  15147. semicolon();
  15148. return new type({ label: label });
  15149. };
  15150. function for_() {
  15151. expect("(");
  15152. var init = null;
  15153. if (!is("punc", ";")) {
  15154. init = is("keyword", "var")
  15155. ? (next(), var_(true))
  15156. : expression(true, true);
  15157. if (is("operator", "in")) {
  15158. if (init instanceof AST_Var && init.definitions.length > 1)
  15159. croak("Only one variable declaration allowed in for..in loop");
  15160. next();
  15161. return for_in(init);
  15162. }
  15163. }
  15164. return regular_for(init);
  15165. };
  15166. function regular_for(init) {
  15167. expect(";");
  15168. var test = is("punc", ";") ? null : expression(true);
  15169. expect(";");
  15170. var step = is("punc", ")") ? null : expression(true);
  15171. expect(")");
  15172. return new AST_For({
  15173. init : init,
  15174. condition : test,
  15175. step : step,
  15176. body : in_loop(statement)
  15177. });
  15178. };
  15179. function for_in(init) {
  15180. var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
  15181. var obj = expression(true);
  15182. expect(")");
  15183. return new AST_ForIn({
  15184. init : init,
  15185. name : lhs,
  15186. object : obj,
  15187. body : in_loop(statement)
  15188. });
  15189. };
  15190. var function_ = function(in_statement, ctor) {
  15191. var is_accessor = ctor === AST_Accessor;
  15192. var name = (is("name") ? as_symbol(in_statement
  15193. ? AST_SymbolDefun
  15194. : is_accessor
  15195. ? AST_SymbolAccessor
  15196. : AST_SymbolLambda)
  15197. : is_accessor && (is("string") || is("num")) ? as_atom_node()
  15198. : null);
  15199. if (in_statement && !name)
  15200. unexpected();
  15201. expect("(");
  15202. if (!ctor) ctor = in_statement ? AST_Defun : AST_Function;
  15203. return new ctor({
  15204. name: name,
  15205. argnames: (function(first, a){
  15206. while (!is("punc", ")")) {
  15207. if (first) first = false; else expect(",");
  15208. a.push(as_symbol(AST_SymbolFunarg));
  15209. }
  15210. next();
  15211. return a;
  15212. })(true, []),
  15213. body: (function(loop, labels){
  15214. ++S.in_function;
  15215. S.in_directives = true;
  15216. S.in_loop = 0;
  15217. S.labels = [];
  15218. var a = block_();
  15219. --S.in_function;
  15220. S.in_loop = loop;
  15221. S.labels = labels;
  15222. return a;
  15223. })(S.in_loop, S.labels)
  15224. });
  15225. };
  15226. function if_() {
  15227. var cond = parenthesised(), body = statement(), belse = null;
  15228. if (is("keyword", "else")) {
  15229. next();
  15230. belse = statement();
  15231. }
  15232. return new AST_If({
  15233. condition : cond,
  15234. body : body,
  15235. alternative : belse
  15236. });
  15237. };
  15238. function block_() {
  15239. expect("{");
  15240. var a = [];
  15241. while (!is("punc", "}")) {
  15242. if (is("eof")) unexpected();
  15243. a.push(statement());
  15244. }
  15245. next();
  15246. return a;
  15247. };
  15248. function switch_body_() {
  15249. expect("{");
  15250. var a = [], cur = null, branch = null, tmp;
  15251. while (!is("punc", "}")) {
  15252. if (is("eof")) unexpected();
  15253. if (is("keyword", "case")) {
  15254. if (branch) branch.end = prev();
  15255. cur = [];
  15256. branch = new AST_Case({
  15257. start : (tmp = S.token, next(), tmp),
  15258. expression : expression(true),
  15259. body : cur
  15260. });
  15261. a.push(branch);
  15262. expect(":");
  15263. }
  15264. else if (is("keyword", "default")) {
  15265. if (branch) branch.end = prev();
  15266. cur = [];
  15267. branch = new AST_Default({
  15268. start : (tmp = S.token, next(), expect(":"), tmp),
  15269. body : cur
  15270. });
  15271. a.push(branch);
  15272. }
  15273. else {
  15274. if (!cur) unexpected();
  15275. cur.push(statement());
  15276. }
  15277. }
  15278. if (branch) branch.end = prev();
  15279. next();
  15280. return a;
  15281. };
  15282. function try_() {
  15283. var body = block_(), bcatch = null, bfinally = null;
  15284. if (is("keyword", "catch")) {
  15285. var start = S.token;
  15286. next();
  15287. expect("(");
  15288. var name = as_symbol(AST_SymbolCatch);
  15289. expect(")");
  15290. bcatch = new AST_Catch({
  15291. start : start,
  15292. argname : name,
  15293. body : block_(),
  15294. end : prev()
  15295. });
  15296. }
  15297. if (is("keyword", "finally")) {
  15298. var start = S.token;
  15299. next();
  15300. bfinally = new AST_Finally({
  15301. start : start,
  15302. body : block_(),
  15303. end : prev()
  15304. });
  15305. }
  15306. if (!bcatch && !bfinally)
  15307. croak("Missing catch/finally blocks");
  15308. return new AST_Try({
  15309. body : body,
  15310. bcatch : bcatch,
  15311. bfinally : bfinally
  15312. });
  15313. };
  15314. function vardefs(no_in, in_const) {
  15315. var a = [];
  15316. for (;;) {
  15317. a.push(new AST_VarDef({
  15318. start : S.token,
  15319. name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
  15320. value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
  15321. end : prev()
  15322. }));
  15323. if (!is("punc", ","))
  15324. break;
  15325. next();
  15326. }
  15327. return a;
  15328. };
  15329. var var_ = function(no_in) {
  15330. return new AST_Var({
  15331. start : prev(),
  15332. definitions : vardefs(no_in, false),
  15333. end : prev()
  15334. });
  15335. };
  15336. var const_ = function() {
  15337. return new AST_Const({
  15338. start : prev(),
  15339. definitions : vardefs(false, true),
  15340. end : prev()
  15341. });
  15342. };
  15343. var new_ = function() {
  15344. var start = S.token;
  15345. expect_token("operator", "new");
  15346. var newexp = expr_atom(false), args;
  15347. if (is("punc", "(")) {
  15348. next();
  15349. args = expr_list(")");
  15350. } else {
  15351. args = [];
  15352. }
  15353. return subscripts(new AST_New({
  15354. start : start,
  15355. expression : newexp,
  15356. args : args,
  15357. end : prev()
  15358. }), true);
  15359. };
  15360. function as_atom_node() {
  15361. var tok = S.token, ret;
  15362. switch (tok.type) {
  15363. case "name":
  15364. return as_symbol(AST_SymbolRef);
  15365. case "num":
  15366. ret = new AST_Number({ start: tok, end: tok, value: tok.value });
  15367. break;
  15368. case "string":
  15369. ret = new AST_String({ start: tok, end: tok, value: tok.value });
  15370. break;
  15371. case "regexp":
  15372. ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
  15373. break;
  15374. case "atom":
  15375. switch (tok.value) {
  15376. case "false":
  15377. ret = new AST_False({ start: tok, end: tok });
  15378. break;
  15379. case "true":
  15380. ret = new AST_True({ start: tok, end: tok });
  15381. break;
  15382. case "null":
  15383. ret = new AST_Null({ start: tok, end: tok });
  15384. break;
  15385. }
  15386. break;
  15387. }
  15388. next();
  15389. return ret;
  15390. };
  15391. var expr_atom = function(allow_calls) {
  15392. if (is("operator", "new")) {
  15393. return new_();
  15394. }
  15395. var start = S.token;
  15396. if (is("punc")) {
  15397. switch (start.value) {
  15398. case "(":
  15399. next();
  15400. var ex = expression(true);
  15401. ex.start = start;
  15402. ex.end = S.token;
  15403. expect(")");
  15404. return subscripts(ex, allow_calls);
  15405. case "[":
  15406. return subscripts(array_(), allow_calls);
  15407. case "{":
  15408. return subscripts(object_(), allow_calls);
  15409. }
  15410. unexpected();
  15411. }
  15412. if (is("keyword", "function")) {
  15413. next();
  15414. var func = function_(false);
  15415. func.start = start;
  15416. func.end = prev();
  15417. return subscripts(func, allow_calls);
  15418. }
  15419. if (ATOMIC_START_TOKEN[S.token.type]) {
  15420. return subscripts(as_atom_node(), allow_calls);
  15421. }
  15422. unexpected();
  15423. };
  15424. function expr_list(closing, allow_trailing_comma, allow_empty) {
  15425. var first = true, a = [];
  15426. while (!is("punc", closing)) {
  15427. if (first) first = false; else expect(",");
  15428. if (allow_trailing_comma && is("punc", closing)) break;
  15429. if (is("punc", ",") && allow_empty) {
  15430. a.push(new AST_Hole({ start: S.token, end: S.token }));
  15431. } else {
  15432. a.push(expression(false));
  15433. }
  15434. }
  15435. next();
  15436. return a;
  15437. };
  15438. var array_ = embed_tokens(function() {
  15439. expect("[");
  15440. return new AST_Array({
  15441. elements: expr_list("]", !options.strict, true)
  15442. });
  15443. });
  15444. var object_ = embed_tokens(function() {
  15445. expect("{");
  15446. var first = true, a = [];
  15447. while (!is("punc", "}")) {
  15448. if (first) first = false; else expect(",");
  15449. if (!options.strict && is("punc", "}"))
  15450. // allow trailing comma
  15451. break;
  15452. var start = S.token;
  15453. var type = start.type;
  15454. var name = as_property_name();
  15455. if (type == "name" && !is("punc", ":")) {
  15456. if (name == "get") {
  15457. a.push(new AST_ObjectGetter({
  15458. start : start,
  15459. key : name,
  15460. value : function_(false, AST_Accessor),
  15461. end : prev()
  15462. }));
  15463. continue;
  15464. }
  15465. if (name == "set") {
  15466. a.push(new AST_ObjectSetter({
  15467. start : start,
  15468. key : name,
  15469. value : function_(false, AST_Accessor),
  15470. end : prev()
  15471. }));
  15472. continue;
  15473. }
  15474. }
  15475. expect(":");
  15476. a.push(new AST_ObjectKeyVal({
  15477. start : start,
  15478. key : name,
  15479. value : expression(false),
  15480. end : prev()
  15481. }));
  15482. }
  15483. next();
  15484. return new AST_Object({ properties: a });
  15485. });
  15486. function as_property_name() {
  15487. var tmp = S.token;
  15488. next();
  15489. switch (tmp.type) {
  15490. case "num":
  15491. case "string":
  15492. case "name":
  15493. case "operator":
  15494. case "keyword":
  15495. case "atom":
  15496. return tmp.value;
  15497. default:
  15498. unexpected();
  15499. }
  15500. };
  15501. function as_name() {
  15502. var tmp = S.token;
  15503. next();
  15504. switch (tmp.type) {
  15505. case "name":
  15506. case "operator":
  15507. case "keyword":
  15508. case "atom":
  15509. return tmp.value;
  15510. default:
  15511. unexpected();
  15512. }
  15513. };
  15514. function as_symbol(type, noerror) {
  15515. if (!is("name")) {
  15516. if (!noerror) croak("Name expected");
  15517. return null;
  15518. }
  15519. var name = S.token.value;
  15520. var sym = new (name == "this" ? AST_This : type)({
  15521. name : String(S.token.value),
  15522. start : S.token,
  15523. end : S.token
  15524. });
  15525. next();
  15526. return sym;
  15527. };
  15528. var subscripts = function(expr, allow_calls) {
  15529. var start = expr.start;
  15530. if (is("punc", ".")) {
  15531. next();
  15532. return subscripts(new AST_Dot({
  15533. start : start,
  15534. expression : expr,
  15535. property : as_name(),
  15536. end : prev()
  15537. }), allow_calls);
  15538. }
  15539. if (is("punc", "[")) {
  15540. next();
  15541. var prop = expression(true);
  15542. expect("]");
  15543. return subscripts(new AST_Sub({
  15544. start : start,
  15545. expression : expr,
  15546. property : prop,
  15547. end : prev()
  15548. }), allow_calls);
  15549. }
  15550. if (allow_calls && is("punc", "(")) {
  15551. next();
  15552. return subscripts(new AST_Call({
  15553. start : start,
  15554. expression : expr,
  15555. args : expr_list(")"),
  15556. end : prev()
  15557. }), true);
  15558. }
  15559. return expr;
  15560. };
  15561. var maybe_unary = function(allow_calls) {
  15562. var start = S.token;
  15563. if (is("operator") && UNARY_PREFIX(start.value)) {
  15564. next();
  15565. var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
  15566. ex.start = start;
  15567. ex.end = prev();
  15568. return ex;
  15569. }
  15570. var val = expr_atom(allow_calls);
  15571. while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
  15572. val = make_unary(AST_UnaryPostfix, S.token.value, val);
  15573. val.start = start;
  15574. val.end = S.token;
  15575. next();
  15576. }
  15577. return val;
  15578. };
  15579. function make_unary(ctor, op, expr) {
  15580. if ((op == "++" || op == "--") && !is_assignable(expr))
  15581. croak("Invalid use of " + op + " operator");
  15582. return new ctor({ operator: op, expression: expr });
  15583. };
  15584. var expr_op = function(left, min_prec, no_in) {
  15585. var op = is("operator") ? S.token.value : null;
  15586. if (op == "in" && no_in) op = null;
  15587. var prec = op != null ? PRECEDENCE[op] : null;
  15588. if (prec != null && prec > min_prec) {
  15589. next();
  15590. var right = expr_op(maybe_unary(true), prec, no_in);
  15591. return expr_op(new AST_Binary({
  15592. start : left.start,
  15593. left : left,
  15594. operator : op,
  15595. right : right,
  15596. end : right.end
  15597. }), min_prec, no_in);
  15598. }
  15599. return left;
  15600. };
  15601. function expr_ops(no_in) {
  15602. return expr_op(maybe_unary(true), 0, no_in);
  15603. };
  15604. var maybe_conditional = function(no_in) {
  15605. var start = S.token;
  15606. var expr = expr_ops(no_in);
  15607. if (is("operator", "?")) {
  15608. next();
  15609. var yes = expression(false);
  15610. expect(":");
  15611. return new AST_Conditional({
  15612. start : start,
  15613. condition : expr,
  15614. consequent : yes,
  15615. alternative : expression(false, no_in),
  15616. end : peek()
  15617. });
  15618. }
  15619. return expr;
  15620. };
  15621. function is_assignable(expr) {
  15622. if (!options.strict) return true;
  15623. if (expr instanceof AST_This) return false;
  15624. return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
  15625. };
  15626. var maybe_assign = function(no_in) {
  15627. var start = S.token;
  15628. var left = maybe_conditional(no_in), val = S.token.value;
  15629. if (is("operator") && ASSIGNMENT(val)) {
  15630. if (is_assignable(left)) {
  15631. next();
  15632. return new AST_Assign({
  15633. start : start,
  15634. left : left,
  15635. operator : val,
  15636. right : maybe_assign(no_in),
  15637. end : prev()
  15638. });
  15639. }
  15640. croak("Invalid assignment");
  15641. }
  15642. return left;
  15643. };
  15644. var expression = function(commas, no_in) {
  15645. var start = S.token;
  15646. var expr = maybe_assign(no_in);
  15647. if (commas && is("punc", ",")) {
  15648. next();
  15649. return new AST_Seq({
  15650. start : start,
  15651. car : expr,
  15652. cdr : expression(true, no_in),
  15653. end : peek()
  15654. });
  15655. }
  15656. return expr;
  15657. };
  15658. function in_loop(cont) {
  15659. ++S.in_loop;
  15660. var ret = cont();
  15661. --S.in_loop;
  15662. return ret;
  15663. };
  15664. if (options.expression) {
  15665. return expression(true);
  15666. }
  15667. return (function(){
  15668. var start = S.token;
  15669. var body = [];
  15670. while (!is("eof"))
  15671. body.push(statement());
  15672. var end = prev();
  15673. var toplevel = options.toplevel;
  15674. if (toplevel) {
  15675. toplevel.body = toplevel.body.concat(body);
  15676. toplevel.end = end;
  15677. } else {
  15678. toplevel = new AST_Toplevel({ start: start, body: body, end: end });
  15679. }
  15680. return toplevel;
  15681. })();
  15682. };
  15683. /***********************************************************************
  15684. A JavaScript tokenizer / parser / beautifier / compressor.
  15685. https://github.com/mishoo/UglifyJS2
  15686. -------------------------------- (C) ---------------------------------
  15687. Author: Mihai Bazon
  15688. <mihai.bazon@gmail.com>
  15689. http://mihai.bazon.net/blog
  15690. Distributed under the BSD license:
  15691. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  15692. Redistribution and use in source and binary forms, with or without
  15693. modification, are permitted provided that the following conditions
  15694. are met:
  15695. * Redistributions of source code must retain the above
  15696. copyright notice, this list of conditions and the following
  15697. disclaimer.
  15698. * Redistributions in binary form must reproduce the above
  15699. copyright notice, this list of conditions and the following
  15700. disclaimer in the documentation and/or other materials
  15701. provided with the distribution.
  15702. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  15703. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15704. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  15705. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  15706. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  15707. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  15708. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  15709. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  15710. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  15711. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15712. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  15713. SUCH DAMAGE.
  15714. ***********************************************************************/
  15715. "use strict";
  15716. // Tree transformer helpers.
  15717. function TreeTransformer(before, after) {
  15718. TreeWalker.call(this);
  15719. this.before = before;
  15720. this.after = after;
  15721. }
  15722. TreeTransformer.prototype = new TreeWalker;
  15723. (function(undefined){
  15724. function _(node, descend) {
  15725. node.DEFMETHOD("transform", function(tw, in_list){
  15726. var x, y;
  15727. tw.push(this);
  15728. if (tw.before) x = tw.before(this, descend, in_list);
  15729. if (x === undefined) {
  15730. if (!tw.after) {
  15731. x = this;
  15732. descend(x, tw);
  15733. } else {
  15734. tw.stack[tw.stack.length - 1] = x = this.clone();
  15735. descend(x, tw);
  15736. y = tw.after(x, in_list);
  15737. if (y !== undefined) x = y;
  15738. }
  15739. }
  15740. tw.pop();
  15741. return x;
  15742. });
  15743. };
  15744. function do_list(list, tw) {
  15745. return MAP(list, function(node){
  15746. return node.transform(tw, true);
  15747. });
  15748. };
  15749. _(AST_Node, noop);
  15750. _(AST_LabeledStatement, function(self, tw){
  15751. self.label = self.label.transform(tw);
  15752. self.body = self.body.transform(tw);
  15753. });
  15754. _(AST_SimpleStatement, function(self, tw){
  15755. self.body = self.body.transform(tw);
  15756. });
  15757. _(AST_Block, function(self, tw){
  15758. self.body = do_list(self.body, tw);
  15759. });
  15760. _(AST_DWLoop, function(self, tw){
  15761. self.condition = self.condition.transform(tw);
  15762. self.body = self.body.transform(tw);
  15763. });
  15764. _(AST_For, function(self, tw){
  15765. if (self.init) self.init = self.init.transform(tw);
  15766. if (self.condition) self.condition = self.condition.transform(tw);
  15767. if (self.step) self.step = self.step.transform(tw);
  15768. self.body = self.body.transform(tw);
  15769. });
  15770. _(AST_ForIn, function(self, tw){
  15771. self.init = self.init.transform(tw);
  15772. self.object = self.object.transform(tw);
  15773. self.body = self.body.transform(tw);
  15774. });
  15775. _(AST_With, function(self, tw){
  15776. self.expression = self.expression.transform(tw);
  15777. self.body = self.body.transform(tw);
  15778. });
  15779. _(AST_Exit, function(self, tw){
  15780. if (self.value) self.value = self.value.transform(tw);
  15781. });
  15782. _(AST_LoopControl, function(self, tw){
  15783. if (self.label) self.label = self.label.transform(tw);
  15784. });
  15785. _(AST_If, function(self, tw){
  15786. self.condition = self.condition.transform(tw);
  15787. self.body = self.body.transform(tw);
  15788. if (self.alternative) self.alternative = self.alternative.transform(tw);
  15789. });
  15790. _(AST_Switch, function(self, tw){
  15791. self.expression = self.expression.transform(tw);
  15792. self.body = do_list(self.body, tw);
  15793. });
  15794. _(AST_Case, function(self, tw){
  15795. self.expression = self.expression.transform(tw);
  15796. self.body = do_list(self.body, tw);
  15797. });
  15798. _(AST_Try, function(self, tw){
  15799. self.body = do_list(self.body, tw);
  15800. if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
  15801. if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
  15802. });
  15803. _(AST_Catch, function(self, tw){
  15804. self.argname = self.argname.transform(tw);
  15805. self.body = do_list(self.body, tw);
  15806. });
  15807. _(AST_Definitions, function(self, tw){
  15808. self.definitions = do_list(self.definitions, tw);
  15809. });
  15810. _(AST_VarDef, function(self, tw){
  15811. self.name = self.name.transform(tw);
  15812. if (self.value) self.value = self.value.transform(tw);
  15813. });
  15814. _(AST_Lambda, function(self, tw){
  15815. if (self.name) self.name = self.name.transform(tw);
  15816. self.argnames = do_list(self.argnames, tw);
  15817. self.body = do_list(self.body, tw);
  15818. });
  15819. _(AST_Call, function(self, tw){
  15820. self.expression = self.expression.transform(tw);
  15821. self.args = do_list(self.args, tw);
  15822. });
  15823. _(AST_Seq, function(self, tw){
  15824. self.car = self.car.transform(tw);
  15825. self.cdr = self.cdr.transform(tw);
  15826. });
  15827. _(AST_Dot, function(self, tw){
  15828. self.expression = self.expression.transform(tw);
  15829. });
  15830. _(AST_Sub, function(self, tw){
  15831. self.expression = self.expression.transform(tw);
  15832. self.property = self.property.transform(tw);
  15833. });
  15834. _(AST_Unary, function(self, tw){
  15835. self.expression = self.expression.transform(tw);
  15836. });
  15837. _(AST_Binary, function(self, tw){
  15838. self.left = self.left.transform(tw);
  15839. self.right = self.right.transform(tw);
  15840. });
  15841. _(AST_Conditional, function(self, tw){
  15842. self.condition = self.condition.transform(tw);
  15843. self.consequent = self.consequent.transform(tw);
  15844. self.alternative = self.alternative.transform(tw);
  15845. });
  15846. _(AST_Array, function(self, tw){
  15847. self.elements = do_list(self.elements, tw);
  15848. });
  15849. _(AST_Object, function(self, tw){
  15850. self.properties = do_list(self.properties, tw);
  15851. });
  15852. _(AST_ObjectProperty, function(self, tw){
  15853. self.value = self.value.transform(tw);
  15854. });
  15855. })();
  15856. /***********************************************************************
  15857. A JavaScript tokenizer / parser / beautifier / compressor.
  15858. https://github.com/mishoo/UglifyJS2
  15859. -------------------------------- (C) ---------------------------------
  15860. Author: Mihai Bazon
  15861. <mihai.bazon@gmail.com>
  15862. http://mihai.bazon.net/blog
  15863. Distributed under the BSD license:
  15864. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  15865. Redistribution and use in source and binary forms, with or without
  15866. modification, are permitted provided that the following conditions
  15867. are met:
  15868. * Redistributions of source code must retain the above
  15869. copyright notice, this list of conditions and the following
  15870. disclaimer.
  15871. * Redistributions in binary form must reproduce the above
  15872. copyright notice, this list of conditions and the following
  15873. disclaimer in the documentation and/or other materials
  15874. provided with the distribution.
  15875. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  15876. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15877. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  15878. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  15879. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  15880. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  15881. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  15882. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  15883. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  15884. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15885. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  15886. SUCH DAMAGE.
  15887. ***********************************************************************/
  15888. "use strict";
  15889. function SymbolDef(scope, index, orig) {
  15890. this.name = orig.name;
  15891. this.orig = [ orig ];
  15892. this.scope = scope;
  15893. this.references = [];
  15894. this.global = false;
  15895. this.mangled_name = null;
  15896. this.undeclared = false;
  15897. this.constant = false;
  15898. this.index = index;
  15899. };
  15900. SymbolDef.prototype = {
  15901. unmangleable: function(options) {
  15902. return (this.global && !(options && options.toplevel))
  15903. || this.undeclared
  15904. || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with));
  15905. },
  15906. mangle: function(options) {
  15907. if (!this.mangled_name && !this.unmangleable(options)) {
  15908. var s = this.scope;
  15909. if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8)
  15910. s = s.parent_scope;
  15911. this.mangled_name = s.next_mangled(options);
  15912. }
  15913. }
  15914. };
  15915. AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
  15916. // This does what ast_add_scope did in UglifyJS v1.
  15917. //
  15918. // Part of it could be done at parse time, but it would complicate
  15919. // the parser (and it's already kinda complex). It's also worth
  15920. // having it separated because we might need to call it multiple
  15921. // times on the same tree.
  15922. // pass 1: setup scope chaining and handle definitions
  15923. var self = this;
  15924. var scope = self.parent_scope = null;
  15925. var labels = new Dictionary();
  15926. var nesting = 0;
  15927. var tw = new TreeWalker(function(node, descend){
  15928. if (node instanceof AST_Scope) {
  15929. node.init_scope_vars(nesting);
  15930. var save_scope = node.parent_scope = scope;
  15931. var save_labels = labels;
  15932. ++nesting;
  15933. scope = node;
  15934. labels = new Dictionary();
  15935. descend();
  15936. labels = save_labels;
  15937. scope = save_scope;
  15938. --nesting;
  15939. return true; // don't descend again in TreeWalker
  15940. }
  15941. if (node instanceof AST_Directive) {
  15942. node.scope = scope;
  15943. push_uniq(scope.directives, node.value);
  15944. return true;
  15945. }
  15946. if (node instanceof AST_With) {
  15947. for (var s = scope; s; s = s.parent_scope)
  15948. s.uses_with = true;
  15949. return;
  15950. }
  15951. if (node instanceof AST_LabeledStatement) {
  15952. var l = node.label;
  15953. if (labels.has(l.name))
  15954. throw new Error(string_template("Label {name} defined twice", l));
  15955. labels.set(l.name, l);
  15956. descend();
  15957. labels.del(l.name);
  15958. return true; // no descend again
  15959. }
  15960. if (node instanceof AST_Symbol) {
  15961. node.scope = scope;
  15962. }
  15963. if (node instanceof AST_Label) {
  15964. node.thedef = node;
  15965. node.init_scope_vars();
  15966. }
  15967. if (node instanceof AST_SymbolLambda) {
  15968. scope.def_function(node);
  15969. }
  15970. else if (node instanceof AST_SymbolDefun) {
  15971. // Careful here, the scope where this should be defined is
  15972. // the parent scope. The reason is that we enter a new
  15973. // scope when we encounter the AST_Defun node (which is
  15974. // instanceof AST_Scope) but we get to the symbol a bit
  15975. // later.
  15976. (node.scope = scope.parent_scope).def_function(node);
  15977. }
  15978. else if (node instanceof AST_SymbolVar
  15979. || node instanceof AST_SymbolConst) {
  15980. var def = scope.def_variable(node);
  15981. def.constant = node instanceof AST_SymbolConst;
  15982. def.init = tw.parent().value;
  15983. }
  15984. else if (node instanceof AST_SymbolCatch) {
  15985. // XXX: this is wrong according to ECMA-262 (12.4). the
  15986. // `catch` argument name should be visible only inside the
  15987. // catch block. For a quick fix AST_Catch should inherit
  15988. // from AST_Scope. Keeping it this way because of IE,
  15989. // which doesn't obey the standard. (it introduces the
  15990. // identifier in the enclosing scope)
  15991. scope.def_variable(node);
  15992. }
  15993. if (node instanceof AST_LabelRef) {
  15994. var sym = labels.get(node.name);
  15995. if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
  15996. name: node.name,
  15997. line: node.start.line,
  15998. col: node.start.col
  15999. }));
  16000. node.thedef = sym;
  16001. }
  16002. });
  16003. self.walk(tw);
  16004. // pass 2: find back references and eval
  16005. var func = null;
  16006. var globals = self.globals = new Dictionary();
  16007. var tw = new TreeWalker(function(node, descend){
  16008. if (node instanceof AST_Lambda) {
  16009. var prev_func = func;
  16010. func = node;
  16011. descend();
  16012. func = prev_func;
  16013. return true;
  16014. }
  16015. if (node instanceof AST_LabelRef) {
  16016. node.reference();
  16017. return true;
  16018. }
  16019. if (node instanceof AST_SymbolRef) {
  16020. var name = node.name;
  16021. var sym = node.scope.find_variable(name);
  16022. if (!sym) {
  16023. var g;
  16024. if (globals.has(name)) {
  16025. g = globals.get(name);
  16026. } else {
  16027. g = new SymbolDef(self, globals.size(), node);
  16028. g.undeclared = true;
  16029. g.global = true;
  16030. globals.set(name, g);
  16031. }
  16032. node.thedef = g;
  16033. if (name == "eval" && tw.parent() instanceof AST_Call) {
  16034. for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
  16035. s.uses_eval = true;
  16036. }
  16037. if (name == "arguments") {
  16038. func.uses_arguments = true;
  16039. }
  16040. } else {
  16041. node.thedef = sym;
  16042. }
  16043. node.reference();
  16044. return true;
  16045. }
  16046. });
  16047. self.walk(tw);
  16048. });
  16049. AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
  16050. this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
  16051. this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
  16052. this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
  16053. this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
  16054. this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
  16055. this.parent_scope = null; // the parent scope
  16056. this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
  16057. this.cname = -1; // the current index for mangling functions/variables
  16058. this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
  16059. });
  16060. AST_Scope.DEFMETHOD("strict", function(){
  16061. return this.has_directive("use strict");
  16062. });
  16063. AST_Lambda.DEFMETHOD("init_scope_vars", function(){
  16064. AST_Scope.prototype.init_scope_vars.apply(this, arguments);
  16065. this.uses_arguments = false;
  16066. });
  16067. AST_SymbolRef.DEFMETHOD("reference", function() {
  16068. var def = this.definition();
  16069. def.references.push(this);
  16070. var s = this.scope;
  16071. while (s) {
  16072. push_uniq(s.enclosed, def);
  16073. if (s === def.scope) break;
  16074. s = s.parent_scope;
  16075. }
  16076. this.frame = this.scope.nesting - def.scope.nesting;
  16077. });
  16078. AST_Label.DEFMETHOD("init_scope_vars", function(){
  16079. this.references = [];
  16080. });
  16081. AST_LabelRef.DEFMETHOD("reference", function(){
  16082. this.thedef.references.push(this);
  16083. });
  16084. AST_Scope.DEFMETHOD("find_variable", function(name){
  16085. if (name instanceof AST_Symbol) name = name.name;
  16086. return this.variables.get(name)
  16087. || (this.parent_scope && this.parent_scope.find_variable(name));
  16088. });
  16089. AST_Scope.DEFMETHOD("has_directive", function(value){
  16090. return this.parent_scope && this.parent_scope.has_directive(value)
  16091. || (this.directives.indexOf(value) >= 0 ? this : null);
  16092. });
  16093. AST_Scope.DEFMETHOD("def_function", function(symbol){
  16094. this.functions.set(symbol.name, this.def_variable(symbol));
  16095. });
  16096. AST_Scope.DEFMETHOD("def_variable", function(symbol){
  16097. var def;
  16098. if (!this.variables.has(symbol.name)) {
  16099. def = new SymbolDef(this, this.variables.size(), symbol);
  16100. this.variables.set(symbol.name, def);
  16101. def.global = !this.parent_scope;
  16102. } else {
  16103. def = this.variables.get(symbol.name);
  16104. def.orig.push(symbol);
  16105. }
  16106. return symbol.thedef = def;
  16107. });
  16108. AST_Scope.DEFMETHOD("next_mangled", function(options){
  16109. var ext = this.enclosed;
  16110. out: while (true) {
  16111. var m = base54(++this.cname);
  16112. if (!is_identifier(m)) continue; // skip over "do"
  16113. // we must ensure that the mangled name does not shadow a name
  16114. // from some parent scope that is referenced in this or in
  16115. // inner scopes.
  16116. for (var i = ext.length; --i >= 0;) {
  16117. var sym = ext[i];
  16118. var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
  16119. if (m == name) continue out;
  16120. }
  16121. return m;
  16122. }
  16123. });
  16124. AST_Scope.DEFMETHOD("references", function(sym){
  16125. if (sym instanceof AST_Symbol) sym = sym.definition();
  16126. return this.enclosed.indexOf(sym) < 0 ? null : sym;
  16127. });
  16128. AST_Symbol.DEFMETHOD("unmangleable", function(options){
  16129. return this.definition().unmangleable(options);
  16130. });
  16131. // property accessors are not mangleable
  16132. AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
  16133. return true;
  16134. });
  16135. // labels are always mangleable
  16136. AST_Label.DEFMETHOD("unmangleable", function(){
  16137. return false;
  16138. });
  16139. AST_Symbol.DEFMETHOD("unreferenced", function(){
  16140. return this.definition().references.length == 0
  16141. && !(this.scope.uses_eval || this.scope.uses_with);
  16142. });
  16143. AST_Symbol.DEFMETHOD("undeclared", function(){
  16144. return this.definition().undeclared;
  16145. });
  16146. AST_LabelRef.DEFMETHOD("undeclared", function(){
  16147. return false;
  16148. });
  16149. AST_Label.DEFMETHOD("undeclared", function(){
  16150. return false;
  16151. });
  16152. AST_Symbol.DEFMETHOD("definition", function(){
  16153. return this.thedef;
  16154. });
  16155. AST_Symbol.DEFMETHOD("global", function(){
  16156. return this.definition().global;
  16157. });
  16158. AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
  16159. return defaults(options, {
  16160. except : [],
  16161. eval : false,
  16162. sort : false,
  16163. toplevel : false,
  16164. screw_ie8 : false
  16165. });
  16166. });
  16167. AST_Toplevel.DEFMETHOD("mangle_names", function(options){
  16168. options = this._default_mangler_options(options);
  16169. // We only need to mangle declaration nodes. Special logic wired
  16170. // into the code generator will display the mangled name if it's
  16171. // present (and for AST_SymbolRef-s it'll use the mangled name of
  16172. // the AST_SymbolDeclaration that it points to).
  16173. var lname = -1;
  16174. var to_mangle = [];
  16175. var tw = new TreeWalker(function(node, descend){
  16176. if (node instanceof AST_LabeledStatement) {
  16177. // lname is incremented when we get to the AST_Label
  16178. var save_nesting = lname;
  16179. descend();
  16180. lname = save_nesting;
  16181. return true; // don't descend again in TreeWalker
  16182. }
  16183. if (node instanceof AST_Scope) {
  16184. var p = tw.parent(), a = [];
  16185. node.variables.each(function(symbol){
  16186. if (options.except.indexOf(symbol.name) < 0) {
  16187. a.push(symbol);
  16188. }
  16189. });
  16190. if (options.sort) a.sort(function(a, b){
  16191. return b.references.length - a.references.length;
  16192. });
  16193. to_mangle.push.apply(to_mangle, a);
  16194. return;
  16195. }
  16196. if (node instanceof AST_Label) {
  16197. var name;
  16198. do name = base54(++lname); while (!is_identifier(name));
  16199. node.mangled_name = name;
  16200. return true;
  16201. }
  16202. });
  16203. this.walk(tw);
  16204. to_mangle.forEach(function(def){ def.mangle(options) });
  16205. });
  16206. AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
  16207. options = this._default_mangler_options(options);
  16208. var tw = new TreeWalker(function(node){
  16209. if (node instanceof AST_Constant)
  16210. base54.consider(node.print_to_string());
  16211. else if (node instanceof AST_Return)
  16212. base54.consider("return");
  16213. else if (node instanceof AST_Throw)
  16214. base54.consider("throw");
  16215. else if (node instanceof AST_Continue)
  16216. base54.consider("continue");
  16217. else if (node instanceof AST_Break)
  16218. base54.consider("break");
  16219. else if (node instanceof AST_Debugger)
  16220. base54.consider("debugger");
  16221. else if (node instanceof AST_Directive)
  16222. base54.consider(node.value);
  16223. else if (node instanceof AST_While)
  16224. base54.consider("while");
  16225. else if (node instanceof AST_Do)
  16226. base54.consider("do while");
  16227. else if (node instanceof AST_If) {
  16228. base54.consider("if");
  16229. if (node.alternative) base54.consider("else");
  16230. }
  16231. else if (node instanceof AST_Var)
  16232. base54.consider("var");
  16233. else if (node instanceof AST_Const)
  16234. base54.consider("const");
  16235. else if (node instanceof AST_Lambda)
  16236. base54.consider("function");
  16237. else if (node instanceof AST_For)
  16238. base54.consider("for");
  16239. else if (node instanceof AST_ForIn)
  16240. base54.consider("for in");
  16241. else if (node instanceof AST_Switch)
  16242. base54.consider("switch");
  16243. else if (node instanceof AST_Case)
  16244. base54.consider("case");
  16245. else if (node instanceof AST_Default)
  16246. base54.consider("default");
  16247. else if (node instanceof AST_With)
  16248. base54.consider("with");
  16249. else if (node instanceof AST_ObjectSetter)
  16250. base54.consider("set" + node.key);
  16251. else if (node instanceof AST_ObjectGetter)
  16252. base54.consider("get" + node.key);
  16253. else if (node instanceof AST_ObjectKeyVal)
  16254. base54.consider(node.key);
  16255. else if (node instanceof AST_New)
  16256. base54.consider("new");
  16257. else if (node instanceof AST_This)
  16258. base54.consider("this");
  16259. else if (node instanceof AST_Try)
  16260. base54.consider("try");
  16261. else if (node instanceof AST_Catch)
  16262. base54.consider("catch");
  16263. else if (node instanceof AST_Finally)
  16264. base54.consider("finally");
  16265. else if (node instanceof AST_Symbol && node.unmangleable(options))
  16266. base54.consider(node.name);
  16267. else if (node instanceof AST_Unary || node instanceof AST_Binary)
  16268. base54.consider(node.operator);
  16269. else if (node instanceof AST_Dot)
  16270. base54.consider(node.property);
  16271. });
  16272. this.walk(tw);
  16273. base54.sort();
  16274. });
  16275. var base54 = (function() {
  16276. var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
  16277. var chars, frequency;
  16278. function reset() {
  16279. frequency = Object.create(null);
  16280. chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
  16281. chars.forEach(function(ch){ frequency[ch] = 0 });
  16282. }
  16283. base54.consider = function(str){
  16284. for (var i = str.length; --i >= 0;) {
  16285. var code = str.charCodeAt(i);
  16286. if (code in frequency) ++frequency[code];
  16287. }
  16288. };
  16289. base54.sort = function() {
  16290. chars = mergeSort(chars, function(a, b){
  16291. if (is_digit(a) && !is_digit(b)) return 1;
  16292. if (is_digit(b) && !is_digit(a)) return -1;
  16293. return frequency[b] - frequency[a];
  16294. });
  16295. };
  16296. base54.reset = reset;
  16297. reset();
  16298. base54.get = function(){ return chars };
  16299. base54.freq = function(){ return frequency };
  16300. function base54(num) {
  16301. var ret = "", base = 54;
  16302. do {
  16303. ret += String.fromCharCode(chars[num % base]);
  16304. num = Math.floor(num / base);
  16305. base = 64;
  16306. } while (num > 0);
  16307. return ret;
  16308. };
  16309. return base54;
  16310. })();
  16311. AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
  16312. options = defaults(options, {
  16313. undeclared : false, // this makes a lot of noise
  16314. unreferenced : true,
  16315. assign_to_global : true,
  16316. func_arguments : true,
  16317. nested_defuns : true,
  16318. eval : true
  16319. });
  16320. var tw = new TreeWalker(function(node){
  16321. if (options.undeclared
  16322. && node instanceof AST_SymbolRef
  16323. && node.undeclared())
  16324. {
  16325. // XXX: this also warns about JS standard names,
  16326. // i.e. Object, Array, parseInt etc. Should add a list of
  16327. // exceptions.
  16328. AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
  16329. name: node.name,
  16330. file: node.start.file,
  16331. line: node.start.line,
  16332. col: node.start.col
  16333. });
  16334. }
  16335. if (options.assign_to_global)
  16336. {
  16337. var sym = null;
  16338. if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
  16339. sym = node.left;
  16340. else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
  16341. sym = node.init;
  16342. if (sym
  16343. && (sym.undeclared()
  16344. || (sym.global() && sym.scope !== sym.definition().scope))) {
  16345. AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
  16346. msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
  16347. name: sym.name,
  16348. file: sym.start.file,
  16349. line: sym.start.line,
  16350. col: sym.start.col
  16351. });
  16352. }
  16353. }
  16354. if (options.eval
  16355. && node instanceof AST_SymbolRef
  16356. && node.undeclared()
  16357. && node.name == "eval") {
  16358. AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
  16359. }
  16360. if (options.unreferenced
  16361. && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
  16362. && node.unreferenced()) {
  16363. AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
  16364. type: node instanceof AST_Label ? "Label" : "Symbol",
  16365. name: node.name,
  16366. file: node.start.file,
  16367. line: node.start.line,
  16368. col: node.start.col
  16369. });
  16370. }
  16371. if (options.func_arguments
  16372. && node instanceof AST_Lambda
  16373. && node.uses_arguments) {
  16374. AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
  16375. name: node.name ? node.name.name : "anonymous",
  16376. file: node.start.file,
  16377. line: node.start.line,
  16378. col: node.start.col
  16379. });
  16380. }
  16381. if (options.nested_defuns
  16382. && node instanceof AST_Defun
  16383. && !(tw.parent() instanceof AST_Scope)) {
  16384. AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
  16385. name: node.name.name,
  16386. type: tw.parent().TYPE,
  16387. file: node.start.file,
  16388. line: node.start.line,
  16389. col: node.start.col
  16390. });
  16391. }
  16392. });
  16393. this.walk(tw);
  16394. });
  16395. /***********************************************************************
  16396. A JavaScript tokenizer / parser / beautifier / compressor.
  16397. https://github.com/mishoo/UglifyJS2
  16398. -------------------------------- (C) ---------------------------------
  16399. Author: Mihai Bazon
  16400. <mihai.bazon@gmail.com>
  16401. http://mihai.bazon.net/blog
  16402. Distributed under the BSD license:
  16403. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  16404. Redistribution and use in source and binary forms, with or without
  16405. modification, are permitted provided that the following conditions
  16406. are met:
  16407. * Redistributions of source code must retain the above
  16408. copyright notice, this list of conditions and the following
  16409. disclaimer.
  16410. * Redistributions in binary form must reproduce the above
  16411. copyright notice, this list of conditions and the following
  16412. disclaimer in the documentation and/or other materials
  16413. provided with the distribution.
  16414. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  16415. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16416. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16417. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  16418. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  16419. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  16420. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  16421. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  16422. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  16423. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  16424. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  16425. SUCH DAMAGE.
  16426. ***********************************************************************/
  16427. "use strict";
  16428. function OutputStream(options) {
  16429. options = defaults(options, {
  16430. indent_start : 0,
  16431. indent_level : 4,
  16432. quote_keys : false,
  16433. space_colon : true,
  16434. ascii_only : false,
  16435. inline_script : false,
  16436. width : 80,
  16437. max_line_len : 32000,
  16438. beautify : false,
  16439. source_map : null,
  16440. bracketize : false,
  16441. semicolons : true,
  16442. comments : false,
  16443. preserve_line : false,
  16444. screw_ie8 : false,
  16445. }, true);
  16446. var indentation = 0;
  16447. var current_col = 0;
  16448. var current_line = 1;
  16449. var current_pos = 0;
  16450. var OUTPUT = "";
  16451. function to_ascii(str, identifier) {
  16452. return str.replace(/[\u0080-\uffff]/g, function(ch) {
  16453. var code = ch.charCodeAt(0).toString(16);
  16454. if (code.length <= 2 && !identifier) {
  16455. while (code.length < 2) code = "0" + code;
  16456. return "\\x" + code;
  16457. } else {
  16458. while (code.length < 4) code = "0" + code;
  16459. return "\\u" + code;
  16460. }
  16461. });
  16462. };
  16463. function make_string(str) {
  16464. var dq = 0, sq = 0;
  16465. str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
  16466. switch (s) {
  16467. case "\\": return "\\\\";
  16468. case "\b": return "\\b";
  16469. case "\f": return "\\f";
  16470. case "\n": return "\\n";
  16471. case "\r": return "\\r";
  16472. case "\u2028": return "\\u2028";
  16473. case "\u2029": return "\\u2029";
  16474. case '"': ++dq; return '"';
  16475. case "'": ++sq; return "'";
  16476. case "\0": return "\\x00";
  16477. }
  16478. return s;
  16479. });
  16480. if (options.ascii_only) str = to_ascii(str);
  16481. if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
  16482. else return '"' + str.replace(/\x22/g, '\\"') + '"';
  16483. };
  16484. function encode_string(str) {
  16485. var ret = make_string(str);
  16486. if (options.inline_script)
  16487. ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
  16488. return ret;
  16489. };
  16490. function make_name(name) {
  16491. name = name.toString();
  16492. if (options.ascii_only)
  16493. name = to_ascii(name, true);
  16494. return name;
  16495. };
  16496. function make_indent(back) {
  16497. return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
  16498. };
  16499. /* -----[ beautification/minification ]----- */
  16500. var might_need_space = false;
  16501. var might_need_semicolon = false;
  16502. var last = null;
  16503. function last_char() {
  16504. return last.charAt(last.length - 1);
  16505. };
  16506. function maybe_newline() {
  16507. if (options.max_line_len && current_col > options.max_line_len)
  16508. print("\n");
  16509. };
  16510. var requireSemicolonChars = makePredicate("( [ + * / - , .");
  16511. function print(str) {
  16512. str = String(str);
  16513. var ch = str.charAt(0);
  16514. if (might_need_semicolon) {
  16515. if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
  16516. if (options.semicolons || requireSemicolonChars(ch)) {
  16517. OUTPUT += ";";
  16518. current_col++;
  16519. current_pos++;
  16520. } else {
  16521. OUTPUT += "\n";
  16522. current_pos++;
  16523. current_line++;
  16524. current_col = 0;
  16525. }
  16526. if (!options.beautify)
  16527. might_need_space = false;
  16528. }
  16529. might_need_semicolon = false;
  16530. maybe_newline();
  16531. }
  16532. if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
  16533. var target_line = stack[stack.length - 1].start.line;
  16534. while (current_line < target_line) {
  16535. OUTPUT += "\n";
  16536. current_pos++;
  16537. current_line++;
  16538. current_col = 0;
  16539. might_need_space = false;
  16540. }
  16541. }
  16542. if (might_need_space) {
  16543. var prev = last_char();
  16544. if ((is_identifier_char(prev)
  16545. && (is_identifier_char(ch) || ch == "\\"))
  16546. || (/^[\+\-\/]$/.test(ch) && ch == prev))
  16547. {
  16548. OUTPUT += " ";
  16549. current_col++;
  16550. current_pos++;
  16551. }
  16552. might_need_space = false;
  16553. }
  16554. var a = str.split(/\r?\n/), n = a.length - 1;
  16555. current_line += n;
  16556. if (n == 0) {
  16557. current_col += a[n].length;
  16558. } else {
  16559. current_col = a[n].length;
  16560. }
  16561. current_pos += str.length;
  16562. last = str;
  16563. OUTPUT += str;
  16564. };
  16565. var space = options.beautify ? function() {
  16566. print(" ");
  16567. } : function() {
  16568. might_need_space = true;
  16569. };
  16570. var indent = options.beautify ? function(half) {
  16571. if (options.beautify) {
  16572. print(make_indent(half ? 0.5 : 0));
  16573. }
  16574. } : noop;
  16575. var with_indent = options.beautify ? function(col, cont) {
  16576. if (col === true) col = next_indent();
  16577. var save_indentation = indentation;
  16578. indentation = col;
  16579. var ret = cont();
  16580. indentation = save_indentation;
  16581. return ret;
  16582. } : function(col, cont) { return cont() };
  16583. var newline = options.beautify ? function() {
  16584. print("\n");
  16585. } : noop;
  16586. var semicolon = options.beautify ? function() {
  16587. print(";");
  16588. } : function() {
  16589. might_need_semicolon = true;
  16590. };
  16591. function force_semicolon() {
  16592. might_need_semicolon = false;
  16593. print(";");
  16594. };
  16595. function next_indent() {
  16596. return indentation + options.indent_level;
  16597. };
  16598. function with_block(cont) {
  16599. var ret;
  16600. print("{");
  16601. newline();
  16602. with_indent(next_indent(), function(){
  16603. ret = cont();
  16604. });
  16605. indent();
  16606. print("}");
  16607. return ret;
  16608. };
  16609. function with_parens(cont) {
  16610. print("(");
  16611. //XXX: still nice to have that for argument lists
  16612. //var ret = with_indent(current_col, cont);
  16613. var ret = cont();
  16614. print(")");
  16615. return ret;
  16616. };
  16617. function with_square(cont) {
  16618. print("[");
  16619. //var ret = with_indent(current_col, cont);
  16620. var ret = cont();
  16621. print("]");
  16622. return ret;
  16623. };
  16624. function comma() {
  16625. print(",");
  16626. space();
  16627. };
  16628. function colon() {
  16629. print(":");
  16630. if (options.space_colon) space();
  16631. };
  16632. var add_mapping = options.source_map ? function(token, name) {
  16633. try {
  16634. if (token) options.source_map.add(
  16635. token.file || "?",
  16636. current_line, current_col,
  16637. token.line, token.col,
  16638. (!name && token.type == "name") ? token.value : name
  16639. );
  16640. } catch(ex) {
  16641. AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
  16642. file: token.file,
  16643. line: token.line,
  16644. col: token.col,
  16645. cline: current_line,
  16646. ccol: current_col,
  16647. name: name || ""
  16648. })
  16649. }
  16650. } : noop;
  16651. function get() {
  16652. return OUTPUT;
  16653. };
  16654. var stack = [];
  16655. return {
  16656. get : get,
  16657. toString : get,
  16658. indent : indent,
  16659. indentation : function() { return indentation },
  16660. current_width : function() { return current_col - indentation },
  16661. should_break : function() { return options.width && this.current_width() >= options.width },
  16662. newline : newline,
  16663. print : print,
  16664. space : space,
  16665. comma : comma,
  16666. colon : colon,
  16667. last : function() { return last },
  16668. semicolon : semicolon,
  16669. force_semicolon : force_semicolon,
  16670. to_ascii : to_ascii,
  16671. print_name : function(name) { print(make_name(name)) },
  16672. print_string : function(str) { print(encode_string(str)) },
  16673. next_indent : next_indent,
  16674. with_indent : with_indent,
  16675. with_block : with_block,
  16676. with_parens : with_parens,
  16677. with_square : with_square,
  16678. add_mapping : add_mapping,
  16679. option : function(opt) { return options[opt] },
  16680. line : function() { return current_line },
  16681. col : function() { return current_col },
  16682. pos : function() { return current_pos },
  16683. push_node : function(node) { stack.push(node) },
  16684. pop_node : function() { return stack.pop() },
  16685. stack : function() { return stack },
  16686. parent : function(n) {
  16687. return stack[stack.length - 2 - (n || 0)];
  16688. }
  16689. };
  16690. };
  16691. /* -----[ code generators ]----- */
  16692. (function(){
  16693. /* -----[ utils ]----- */
  16694. function DEFPRINT(nodetype, generator) {
  16695. nodetype.DEFMETHOD("_codegen", generator);
  16696. };
  16697. AST_Node.DEFMETHOD("print", function(stream, force_parens){
  16698. var self = this, generator = self._codegen;
  16699. function doit() {
  16700. self.add_comments(stream);
  16701. self.add_source_map(stream);
  16702. generator(self, stream);
  16703. }
  16704. stream.push_node(self);
  16705. if (force_parens || self.needs_parens(stream)) {
  16706. stream.with_parens(doit);
  16707. } else {
  16708. doit();
  16709. }
  16710. stream.pop_node();
  16711. });
  16712. AST_Node.DEFMETHOD("print_to_string", function(options){
  16713. var s = OutputStream(options);
  16714. this.print(s);
  16715. return s.get();
  16716. });
  16717. /* -----[ comments ]----- */
  16718. AST_Node.DEFMETHOD("add_comments", function(output){
  16719. var c = output.option("comments"), self = this;
  16720. if (c) {
  16721. var start = self.start;
  16722. if (start && !start._comments_dumped) {
  16723. start._comments_dumped = true;
  16724. var comments = start.comments_before;
  16725. // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
  16726. // if this node is `return` or `throw`, we cannot allow comments before
  16727. // the returned or thrown value.
  16728. if (self instanceof AST_Exit &&
  16729. self.value && self.value.start.comments_before.length > 0) {
  16730. comments = (comments || []).concat(self.value.start.comments_before);
  16731. self.value.start.comments_before = [];
  16732. }
  16733. if (c.test) {
  16734. comments = comments.filter(function(comment){
  16735. return c.test(comment.value);
  16736. });
  16737. } else if (typeof c == "function") {
  16738. comments = comments.filter(function(comment){
  16739. return c(self, comment);
  16740. });
  16741. }
  16742. comments.forEach(function(c){
  16743. if (c.type == "comment1") {
  16744. output.print("//" + c.value + "\n");
  16745. output.indent();
  16746. }
  16747. else if (c.type == "comment2") {
  16748. output.print("/*" + c.value + "*/");
  16749. if (start.nlb) {
  16750. output.print("\n");
  16751. output.indent();
  16752. } else {
  16753. output.space();
  16754. }
  16755. }
  16756. });
  16757. }
  16758. }
  16759. });
  16760. /* -----[ PARENTHESES ]----- */
  16761. function PARENS(nodetype, func) {
  16762. nodetype.DEFMETHOD("needs_parens", func);
  16763. };
  16764. PARENS(AST_Node, function(){
  16765. return false;
  16766. });
  16767. // a function expression needs parens around it when it's provably
  16768. // the first token to appear in a statement.
  16769. PARENS(AST_Function, function(output){
  16770. return first_in_statement(output);
  16771. });
  16772. // same goes for an object literal, because otherwise it would be
  16773. // interpreted as a block of code.
  16774. PARENS(AST_Object, function(output){
  16775. return first_in_statement(output);
  16776. });
  16777. PARENS(AST_Unary, function(output){
  16778. var p = output.parent();
  16779. return p instanceof AST_PropAccess && p.expression === this;
  16780. });
  16781. PARENS(AST_Seq, function(output){
  16782. var p = output.parent();
  16783. return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
  16784. || p instanceof AST_Unary // !(foo, bar, baz)
  16785. || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
  16786. || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
  16787. || p instanceof AST_Dot // (1, {foo:2}).foo ==> 2
  16788. || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
  16789. || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
  16790. || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
  16791. * ==> 20 (side effect, set a := 10 and b := 20) */
  16792. ;
  16793. });
  16794. PARENS(AST_Binary, function(output){
  16795. var p = output.parent();
  16796. // (foo && bar)()
  16797. if (p instanceof AST_Call && p.expression === this)
  16798. return true;
  16799. // typeof (foo && bar)
  16800. if (p instanceof AST_Unary)
  16801. return true;
  16802. // (foo && bar)["prop"], (foo && bar).prop
  16803. if (p instanceof AST_PropAccess && p.expression === this)
  16804. return true;
  16805. // this deals with precedence: 3 * (2 + 1)
  16806. if (p instanceof AST_Binary) {
  16807. var po = p.operator, pp = PRECEDENCE[po];
  16808. var so = this.operator, sp = PRECEDENCE[so];
  16809. if (pp > sp
  16810. || (pp == sp
  16811. && this === p.right
  16812. && !(so == po &&
  16813. (so == "*" ||
  16814. so == "&&" ||
  16815. so == "||")))) {
  16816. return true;
  16817. }
  16818. }
  16819. });
  16820. PARENS(AST_PropAccess, function(output){
  16821. var p = output.parent();
  16822. if (p instanceof AST_New && p.expression === this) {
  16823. // i.e. new (foo.bar().baz)
  16824. //
  16825. // if there's one call into this subtree, then we need
  16826. // parens around it too, otherwise the call will be
  16827. // interpreted as passing the arguments to the upper New
  16828. // expression.
  16829. try {
  16830. this.walk(new TreeWalker(function(node){
  16831. if (node instanceof AST_Call) throw p;
  16832. }));
  16833. } catch(ex) {
  16834. if (ex !== p) throw ex;
  16835. return true;
  16836. }
  16837. }
  16838. });
  16839. PARENS(AST_Call, function(output){
  16840. var p = output.parent();
  16841. return p instanceof AST_New && p.expression === this;
  16842. });
  16843. PARENS(AST_New, function(output){
  16844. var p = output.parent();
  16845. if (no_constructor_parens(this, output)
  16846. && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
  16847. || p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
  16848. return true;
  16849. });
  16850. PARENS(AST_Number, function(output){
  16851. var p = output.parent();
  16852. if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
  16853. return true;
  16854. });
  16855. PARENS(AST_NaN, function(output){
  16856. var p = output.parent();
  16857. if (p instanceof AST_PropAccess && p.expression === this)
  16858. return true;
  16859. });
  16860. function assign_and_conditional_paren_rules(output) {
  16861. var p = output.parent();
  16862. // !(a = false) → true
  16863. if (p instanceof AST_Unary)
  16864. return true;
  16865. // 1 + (a = 2) + 3 → 6, side effect setting a = 2
  16866. if (p instanceof AST_Binary && !(p instanceof AST_Assign))
  16867. return true;
  16868. // (a = func)() —or— new (a = Object)()
  16869. if (p instanceof AST_Call && p.expression === this)
  16870. return true;
  16871. // (a = foo) ? bar : baz
  16872. if (p instanceof AST_Conditional && p.condition === this)
  16873. return true;
  16874. // (a = foo)["prop"] —or— (a = foo).prop
  16875. if (p instanceof AST_PropAccess && p.expression === this)
  16876. return true;
  16877. };
  16878. PARENS(AST_Assign, assign_and_conditional_paren_rules);
  16879. PARENS(AST_Conditional, assign_and_conditional_paren_rules);
  16880. /* -----[ PRINTERS ]----- */
  16881. DEFPRINT(AST_Directive, function(self, output){
  16882. output.print_string(self.value);
  16883. output.semicolon();
  16884. });
  16885. DEFPRINT(AST_Debugger, function(self, output){
  16886. output.print("debugger");
  16887. output.semicolon();
  16888. });
  16889. /* -----[ statements ]----- */
  16890. function display_body(body, is_toplevel, output) {
  16891. var last = body.length - 1;
  16892. body.forEach(function(stmt, i){
  16893. if (!(stmt instanceof AST_EmptyStatement)) {
  16894. output.indent();
  16895. stmt.print(output);
  16896. if (!(i == last && is_toplevel)) {
  16897. output.newline();
  16898. if (is_toplevel) output.newline();
  16899. }
  16900. }
  16901. });
  16902. };
  16903. AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
  16904. force_statement(this.body, output);
  16905. });
  16906. DEFPRINT(AST_Statement, function(self, output){
  16907. self.body.print(output);
  16908. output.semicolon();
  16909. });
  16910. DEFPRINT(AST_Toplevel, function(self, output){
  16911. display_body(self.body, true, output);
  16912. output.print("");
  16913. });
  16914. DEFPRINT(AST_LabeledStatement, function(self, output){
  16915. self.label.print(output);
  16916. output.colon();
  16917. self.body.print(output);
  16918. });
  16919. DEFPRINT(AST_SimpleStatement, function(self, output){
  16920. self.body.print(output);
  16921. output.semicolon();
  16922. });
  16923. function print_bracketed(body, output) {
  16924. if (body.length > 0) output.with_block(function(){
  16925. display_body(body, false, output);
  16926. });
  16927. else output.print("{}");
  16928. };
  16929. DEFPRINT(AST_BlockStatement, function(self, output){
  16930. print_bracketed(self.body, output);
  16931. });
  16932. DEFPRINT(AST_EmptyStatement, function(self, output){
  16933. output.semicolon();
  16934. });
  16935. DEFPRINT(AST_Do, function(self, output){
  16936. output.print("do");
  16937. output.space();
  16938. self._do_print_body(output);
  16939. output.space();
  16940. output.print("while");
  16941. output.space();
  16942. output.with_parens(function(){
  16943. self.condition.print(output);
  16944. });
  16945. output.semicolon();
  16946. });
  16947. DEFPRINT(AST_While, function(self, output){
  16948. output.print("while");
  16949. output.space();
  16950. output.with_parens(function(){
  16951. self.condition.print(output);
  16952. });
  16953. output.space();
  16954. self._do_print_body(output);
  16955. });
  16956. DEFPRINT(AST_For, function(self, output){
  16957. output.print("for");
  16958. output.space();
  16959. output.with_parens(function(){
  16960. if (self.init) {
  16961. if (self.init instanceof AST_Definitions) {
  16962. self.init.print(output);
  16963. } else {
  16964. parenthesize_for_noin(self.init, output, true);
  16965. }
  16966. output.print(";");
  16967. output.space();
  16968. } else {
  16969. output.print(";");
  16970. }
  16971. if (self.condition) {
  16972. self.condition.print(output);
  16973. output.print(";");
  16974. output.space();
  16975. } else {
  16976. output.print(";");
  16977. }
  16978. if (self.step) {
  16979. self.step.print(output);
  16980. }
  16981. });
  16982. output.space();
  16983. self._do_print_body(output);
  16984. });
  16985. DEFPRINT(AST_ForIn, function(self, output){
  16986. output.print("for");
  16987. output.space();
  16988. output.with_parens(function(){
  16989. self.init.print(output);
  16990. output.space();
  16991. output.print("in");
  16992. output.space();
  16993. self.object.print(output);
  16994. });
  16995. output.space();
  16996. self._do_print_body(output);
  16997. });
  16998. DEFPRINT(AST_With, function(self, output){
  16999. output.print("with");
  17000. output.space();
  17001. output.with_parens(function(){
  17002. self.expression.print(output);
  17003. });
  17004. output.space();
  17005. self._do_print_body(output);
  17006. });
  17007. /* -----[ functions ]----- */
  17008. AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
  17009. var self = this;
  17010. if (!nokeyword) {
  17011. output.print("function");
  17012. }
  17013. if (self.name) {
  17014. output.space();
  17015. self.name.print(output);
  17016. }
  17017. output.with_parens(function(){
  17018. self.argnames.forEach(function(arg, i){
  17019. if (i) output.comma();
  17020. arg.print(output);
  17021. });
  17022. });
  17023. output.space();
  17024. print_bracketed(self.body, output);
  17025. });
  17026. DEFPRINT(AST_Lambda, function(self, output){
  17027. self._do_print(output);
  17028. });
  17029. /* -----[ exits ]----- */
  17030. AST_Exit.DEFMETHOD("_do_print", function(output, kind){
  17031. output.print(kind);
  17032. if (this.value) {
  17033. output.space();
  17034. this.value.print(output);
  17035. }
  17036. output.semicolon();
  17037. });
  17038. DEFPRINT(AST_Return, function(self, output){
  17039. self._do_print(output, "return");
  17040. });
  17041. DEFPRINT(AST_Throw, function(self, output){
  17042. self._do_print(output, "throw");
  17043. });
  17044. /* -----[ loop control ]----- */
  17045. AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
  17046. output.print(kind);
  17047. if (this.label) {
  17048. output.space();
  17049. this.label.print(output);
  17050. }
  17051. output.semicolon();
  17052. });
  17053. DEFPRINT(AST_Break, function(self, output){
  17054. self._do_print(output, "break");
  17055. });
  17056. DEFPRINT(AST_Continue, function(self, output){
  17057. self._do_print(output, "continue");
  17058. });
  17059. /* -----[ if ]----- */
  17060. function make_then(self, output) {
  17061. if (output.option("bracketize")) {
  17062. make_block(self.body, output);
  17063. return;
  17064. }
  17065. // The squeezer replaces "block"-s that contain only a single
  17066. // statement with the statement itself; technically, the AST
  17067. // is correct, but this can create problems when we output an
  17068. // IF having an ELSE clause where the THEN clause ends in an
  17069. // IF *without* an ELSE block (then the outer ELSE would refer
  17070. // to the inner IF). This function checks for this case and
  17071. // adds the block brackets if needed.
  17072. if (!self.body)
  17073. return output.force_semicolon();
  17074. if (self.body instanceof AST_Do
  17075. && !output.option("screw_ie8")) {
  17076. // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
  17077. // croaks with "syntax error" on code like this: if (foo)
  17078. // do ... while(cond); else ... we need block brackets
  17079. // around do/while
  17080. make_block(self.body, output);
  17081. return;
  17082. }
  17083. var b = self.body;
  17084. while (true) {
  17085. if (b instanceof AST_If) {
  17086. if (!b.alternative) {
  17087. make_block(self.body, output);
  17088. return;
  17089. }
  17090. b = b.alternative;
  17091. }
  17092. else if (b instanceof AST_StatementWithBody) {
  17093. b = b.body;
  17094. }
  17095. else break;
  17096. }
  17097. force_statement(self.body, output);
  17098. };
  17099. DEFPRINT(AST_If, function(self, output){
  17100. output.print("if");
  17101. output.space();
  17102. output.with_parens(function(){
  17103. self.condition.print(output);
  17104. });
  17105. output.space();
  17106. if (self.alternative) {
  17107. make_then(self, output);
  17108. output.space();
  17109. output.print("else");
  17110. output.space();
  17111. force_statement(self.alternative, output);
  17112. } else {
  17113. self._do_print_body(output);
  17114. }
  17115. });
  17116. /* -----[ switch ]----- */
  17117. DEFPRINT(AST_Switch, function(self, output){
  17118. output.print("switch");
  17119. output.space();
  17120. output.with_parens(function(){
  17121. self.expression.print(output);
  17122. });
  17123. output.space();
  17124. if (self.body.length > 0) output.with_block(function(){
  17125. self.body.forEach(function(stmt, i){
  17126. if (i) output.newline();
  17127. output.indent(true);
  17128. stmt.print(output);
  17129. });
  17130. });
  17131. else output.print("{}");
  17132. });
  17133. AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
  17134. if (this.body.length > 0) {
  17135. output.newline();
  17136. this.body.forEach(function(stmt){
  17137. output.indent();
  17138. stmt.print(output);
  17139. output.newline();
  17140. });
  17141. }
  17142. });
  17143. DEFPRINT(AST_Default, function(self, output){
  17144. output.print("default:");
  17145. self._do_print_body(output);
  17146. });
  17147. DEFPRINT(AST_Case, function(self, output){
  17148. output.print("case");
  17149. output.space();
  17150. self.expression.print(output);
  17151. output.print(":");
  17152. self._do_print_body(output);
  17153. });
  17154. /* -----[ exceptions ]----- */
  17155. DEFPRINT(AST_Try, function(self, output){
  17156. output.print("try");
  17157. output.space();
  17158. print_bracketed(self.body, output);
  17159. if (self.bcatch) {
  17160. output.space();
  17161. self.bcatch.print(output);
  17162. }
  17163. if (self.bfinally) {
  17164. output.space();
  17165. self.bfinally.print(output);
  17166. }
  17167. });
  17168. DEFPRINT(AST_Catch, function(self, output){
  17169. output.print("catch");
  17170. output.space();
  17171. output.with_parens(function(){
  17172. self.argname.print(output);
  17173. });
  17174. output.space();
  17175. print_bracketed(self.body, output);
  17176. });
  17177. DEFPRINT(AST_Finally, function(self, output){
  17178. output.print("finally");
  17179. output.space();
  17180. print_bracketed(self.body, output);
  17181. });
  17182. /* -----[ var/const ]----- */
  17183. AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
  17184. output.print(kind);
  17185. output.space();
  17186. this.definitions.forEach(function(def, i){
  17187. if (i) output.comma();
  17188. def.print(output);
  17189. });
  17190. var p = output.parent();
  17191. var in_for = p instanceof AST_For || p instanceof AST_ForIn;
  17192. var avoid_semicolon = in_for && p.init === this;
  17193. if (!avoid_semicolon)
  17194. output.semicolon();
  17195. });
  17196. DEFPRINT(AST_Var, function(self, output){
  17197. self._do_print(output, "var");
  17198. });
  17199. DEFPRINT(AST_Const, function(self, output){
  17200. self._do_print(output, "const");
  17201. });
  17202. function parenthesize_for_noin(node, output, noin) {
  17203. if (!noin) node.print(output);
  17204. else try {
  17205. // need to take some precautions here:
  17206. // https://github.com/mishoo/UglifyJS2/issues/60
  17207. node.walk(new TreeWalker(function(node){
  17208. if (node instanceof AST_Binary && node.operator == "in")
  17209. throw output;
  17210. }));
  17211. node.print(output);
  17212. } catch(ex) {
  17213. if (ex !== output) throw ex;
  17214. node.print(output, true);
  17215. }
  17216. };
  17217. DEFPRINT(AST_VarDef, function(self, output){
  17218. self.name.print(output);
  17219. if (self.value) {
  17220. output.space();
  17221. output.print("=");
  17222. output.space();
  17223. var p = output.parent(1);
  17224. var noin = p instanceof AST_For || p instanceof AST_ForIn;
  17225. parenthesize_for_noin(self.value, output, noin);
  17226. }
  17227. });
  17228. /* -----[ other expressions ]----- */
  17229. DEFPRINT(AST_Call, function(self, output){
  17230. self.expression.print(output);
  17231. if (self instanceof AST_New && no_constructor_parens(self, output))
  17232. return;
  17233. output.with_parens(function(){
  17234. self.args.forEach(function(expr, i){
  17235. if (i) output.comma();
  17236. expr.print(output);
  17237. });
  17238. });
  17239. });
  17240. DEFPRINT(AST_New, function(self, output){
  17241. output.print("new");
  17242. output.space();
  17243. AST_Call.prototype._codegen(self, output);
  17244. });
  17245. AST_Seq.DEFMETHOD("_do_print", function(output){
  17246. this.car.print(output);
  17247. if (this.cdr) {
  17248. output.comma();
  17249. if (output.should_break()) {
  17250. output.newline();
  17251. output.indent();
  17252. }
  17253. this.cdr.print(output);
  17254. }
  17255. });
  17256. DEFPRINT(AST_Seq, function(self, output){
  17257. self._do_print(output);
  17258. // var p = output.parent();
  17259. // if (p instanceof AST_Statement) {
  17260. // output.with_indent(output.next_indent(), function(){
  17261. // self._do_print(output);
  17262. // });
  17263. // } else {
  17264. // self._do_print(output);
  17265. // }
  17266. });
  17267. DEFPRINT(AST_Dot, function(self, output){
  17268. var expr = self.expression;
  17269. expr.print(output);
  17270. if (expr instanceof AST_Number && expr.getValue() >= 0) {
  17271. if (!/[xa-f.]/i.test(output.last())) {
  17272. output.print(".");
  17273. }
  17274. }
  17275. output.print(".");
  17276. // the name after dot would be mapped about here.
  17277. output.add_mapping(self.end);
  17278. output.print_name(self.property);
  17279. });
  17280. DEFPRINT(AST_Sub, function(self, output){
  17281. self.expression.print(output);
  17282. output.print("[");
  17283. self.property.print(output);
  17284. output.print("]");
  17285. });
  17286. DEFPRINT(AST_UnaryPrefix, function(self, output){
  17287. var op = self.operator;
  17288. output.print(op);
  17289. if (/^[a-z]/i.test(op))
  17290. output.space();
  17291. self.expression.print(output);
  17292. });
  17293. DEFPRINT(AST_UnaryPostfix, function(self, output){
  17294. self.expression.print(output);
  17295. output.print(self.operator);
  17296. });
  17297. DEFPRINT(AST_Binary, function(self, output){
  17298. self.left.print(output);
  17299. output.space();
  17300. output.print(self.operator);
  17301. output.space();
  17302. self.right.print(output);
  17303. });
  17304. DEFPRINT(AST_Conditional, function(self, output){
  17305. self.condition.print(output);
  17306. output.space();
  17307. output.print("?");
  17308. output.space();
  17309. self.consequent.print(output);
  17310. output.space();
  17311. output.colon();
  17312. self.alternative.print(output);
  17313. });
  17314. /* -----[ literals ]----- */
  17315. DEFPRINT(AST_Array, function(self, output){
  17316. output.with_square(function(){
  17317. var a = self.elements, len = a.length;
  17318. if (len > 0) output.space();
  17319. a.forEach(function(exp, i){
  17320. if (i) output.comma();
  17321. exp.print(output);
  17322. // If the final element is a hole, we need to make sure it
  17323. // doesn't look like a trailing comma, by inserting an actual
  17324. // trailing comma.
  17325. if (i === len - 1 && exp instanceof AST_Hole)
  17326. output.comma();
  17327. });
  17328. if (len > 0) output.space();
  17329. });
  17330. });
  17331. DEFPRINT(AST_Object, function(self, output){
  17332. if (self.properties.length > 0) output.with_block(function(){
  17333. self.properties.forEach(function(prop, i){
  17334. if (i) {
  17335. output.print(",");
  17336. output.newline();
  17337. }
  17338. output.indent();
  17339. prop.print(output);
  17340. });
  17341. output.newline();
  17342. });
  17343. else output.print("{}");
  17344. });
  17345. DEFPRINT(AST_ObjectKeyVal, function(self, output){
  17346. var key = self.key;
  17347. if (output.option("quote_keys")) {
  17348. output.print_string(key + "");
  17349. } else if ((typeof key == "number"
  17350. || !output.option("beautify")
  17351. && +key + "" == key)
  17352. && parseFloat(key) >= 0) {
  17353. output.print(make_num(key));
  17354. } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
  17355. output.print_name(key);
  17356. } else {
  17357. output.print_string(key);
  17358. }
  17359. output.colon();
  17360. self.value.print(output);
  17361. });
  17362. DEFPRINT(AST_ObjectSetter, function(self, output){
  17363. output.print("set");
  17364. self.value._do_print(output, true);
  17365. });
  17366. DEFPRINT(AST_ObjectGetter, function(self, output){
  17367. output.print("get");
  17368. self.value._do_print(output, true);
  17369. });
  17370. DEFPRINT(AST_Symbol, function(self, output){
  17371. var def = self.definition();
  17372. output.print_name(def ? def.mangled_name || def.name : self.name);
  17373. });
  17374. DEFPRINT(AST_Undefined, function(self, output){
  17375. output.print("void 0");
  17376. });
  17377. DEFPRINT(AST_Hole, noop);
  17378. DEFPRINT(AST_Infinity, function(self, output){
  17379. output.print("1/0");
  17380. });
  17381. DEFPRINT(AST_NaN, function(self, output){
  17382. output.print("0/0");
  17383. });
  17384. DEFPRINT(AST_This, function(self, output){
  17385. output.print("this");
  17386. });
  17387. DEFPRINT(AST_Constant, function(self, output){
  17388. output.print(self.getValue());
  17389. });
  17390. DEFPRINT(AST_String, function(self, output){
  17391. output.print_string(self.getValue());
  17392. });
  17393. DEFPRINT(AST_Number, function(self, output){
  17394. output.print(make_num(self.getValue()));
  17395. });
  17396. DEFPRINT(AST_RegExp, function(self, output){
  17397. var str = self.getValue().toString();
  17398. if (output.option("ascii_only"))
  17399. str = output.to_ascii(str);
  17400. output.print(str);
  17401. var p = output.parent();
  17402. if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
  17403. output.print(" ");
  17404. });
  17405. function force_statement(stat, output) {
  17406. if (output.option("bracketize")) {
  17407. if (!stat || stat instanceof AST_EmptyStatement)
  17408. output.print("{}");
  17409. else if (stat instanceof AST_BlockStatement)
  17410. stat.print(output);
  17411. else output.with_block(function(){
  17412. output.indent();
  17413. stat.print(output);
  17414. output.newline();
  17415. });
  17416. } else {
  17417. if (!stat || stat instanceof AST_EmptyStatement)
  17418. output.force_semicolon();
  17419. else
  17420. stat.print(output);
  17421. }
  17422. };
  17423. // return true if the node at the top of the stack (that means the
  17424. // innermost node in the current output) is lexically the first in
  17425. // a statement.
  17426. function first_in_statement(output) {
  17427. var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
  17428. while (i > 0) {
  17429. if (p instanceof AST_Statement && p.body === node)
  17430. return true;
  17431. if ((p instanceof AST_Seq && p.car === node ) ||
  17432. (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
  17433. (p instanceof AST_Dot && p.expression === node ) ||
  17434. (p instanceof AST_Sub && p.expression === node ) ||
  17435. (p instanceof AST_Conditional && p.condition === node ) ||
  17436. (p instanceof AST_Binary && p.left === node ) ||
  17437. (p instanceof AST_UnaryPostfix && p.expression === node ))
  17438. {
  17439. node = p;
  17440. p = a[--i];
  17441. } else {
  17442. return false;
  17443. }
  17444. }
  17445. };
  17446. // self should be AST_New. decide if we want to show parens or not.
  17447. function no_constructor_parens(self, output) {
  17448. return self.args.length == 0 && !output.option("beautify");
  17449. };
  17450. function best_of(a) {
  17451. var best = a[0], len = best.length;
  17452. for (var i = 1; i < a.length; ++i) {
  17453. if (a[i].length < len) {
  17454. best = a[i];
  17455. len = best.length;
  17456. }
  17457. }
  17458. return best;
  17459. };
  17460. function make_num(num) {
  17461. var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
  17462. if (Math.floor(num) === num) {
  17463. if (num >= 0) {
  17464. a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
  17465. "0" + num.toString(8)); // same.
  17466. } else {
  17467. a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
  17468. "-0" + (-num).toString(8)); // same.
  17469. }
  17470. if ((m = /^(.*?)(0+)$/.exec(num))) {
  17471. a.push(m[1] + "e" + m[2].length);
  17472. }
  17473. } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
  17474. a.push(m[2] + "e-" + (m[1].length + m[2].length),
  17475. str.substr(str.indexOf(".")));
  17476. }
  17477. return best_of(a);
  17478. };
  17479. function make_block(stmt, output) {
  17480. if (stmt instanceof AST_BlockStatement) {
  17481. stmt.print(output);
  17482. return;
  17483. }
  17484. output.with_block(function(){
  17485. output.indent();
  17486. stmt.print(output);
  17487. output.newline();
  17488. });
  17489. };
  17490. /* -----[ source map generators ]----- */
  17491. function DEFMAP(nodetype, generator) {
  17492. nodetype.DEFMETHOD("add_source_map", function(stream){
  17493. generator(this, stream);
  17494. });
  17495. };
  17496. // We could easily add info for ALL nodes, but it seems to me that
  17497. // would be quite wasteful, hence this noop in the base class.
  17498. DEFMAP(AST_Node, noop);
  17499. function basic_sourcemap_gen(self, output) {
  17500. output.add_mapping(self.start);
  17501. };
  17502. // XXX: I'm not exactly sure if we need it for all of these nodes,
  17503. // or if we should add even more.
  17504. DEFMAP(AST_Directive, basic_sourcemap_gen);
  17505. DEFMAP(AST_Debugger, basic_sourcemap_gen);
  17506. DEFMAP(AST_Symbol, basic_sourcemap_gen);
  17507. DEFMAP(AST_Jump, basic_sourcemap_gen);
  17508. DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
  17509. DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
  17510. DEFMAP(AST_Lambda, basic_sourcemap_gen);
  17511. DEFMAP(AST_Switch, basic_sourcemap_gen);
  17512. DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
  17513. DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
  17514. DEFMAP(AST_Toplevel, noop);
  17515. DEFMAP(AST_New, basic_sourcemap_gen);
  17516. DEFMAP(AST_Try, basic_sourcemap_gen);
  17517. DEFMAP(AST_Catch, basic_sourcemap_gen);
  17518. DEFMAP(AST_Finally, basic_sourcemap_gen);
  17519. DEFMAP(AST_Definitions, basic_sourcemap_gen);
  17520. DEFMAP(AST_Constant, basic_sourcemap_gen);
  17521. DEFMAP(AST_ObjectProperty, function(self, output){
  17522. output.add_mapping(self.start, self.key);
  17523. });
  17524. })();
  17525. /***********************************************************************
  17526. A JavaScript tokenizer / parser / beautifier / compressor.
  17527. https://github.com/mishoo/UglifyJS2
  17528. -------------------------------- (C) ---------------------------------
  17529. Author: Mihai Bazon
  17530. <mihai.bazon@gmail.com>
  17531. http://mihai.bazon.net/blog
  17532. Distributed under the BSD license:
  17533. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  17534. Redistribution and use in source and binary forms, with or without
  17535. modification, are permitted provided that the following conditions
  17536. are met:
  17537. * Redistributions of source code must retain the above
  17538. copyright notice, this list of conditions and the following
  17539. disclaimer.
  17540. * Redistributions in binary form must reproduce the above
  17541. copyright notice, this list of conditions and the following
  17542. disclaimer in the documentation and/or other materials
  17543. provided with the distribution.
  17544. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  17545. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17546. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17547. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  17548. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  17549. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  17550. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  17551. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  17552. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  17553. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  17554. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  17555. SUCH DAMAGE.
  17556. ***********************************************************************/
  17557. "use strict";
  17558. function Compressor(options, false_by_default) {
  17559. if (!(this instanceof Compressor))
  17560. return new Compressor(options, false_by_default);
  17561. TreeTransformer.call(this, this.before, this.after);
  17562. this.options = defaults(options, {
  17563. sequences : !false_by_default,
  17564. properties : !false_by_default,
  17565. dead_code : !false_by_default,
  17566. drop_debugger : !false_by_default,
  17567. unsafe : false,
  17568. unsafe_comps : false,
  17569. conditionals : !false_by_default,
  17570. comparisons : !false_by_default,
  17571. evaluate : !false_by_default,
  17572. booleans : !false_by_default,
  17573. loops : !false_by_default,
  17574. unused : !false_by_default,
  17575. hoist_funs : !false_by_default,
  17576. hoist_vars : false,
  17577. if_return : !false_by_default,
  17578. join_vars : !false_by_default,
  17579. cascade : !false_by_default,
  17580. side_effects : !false_by_default,
  17581. negate_iife : !false_by_default,
  17582. screw_ie8 : false,
  17583. warnings : true,
  17584. global_defs : {}
  17585. }, true);
  17586. };
  17587. Compressor.prototype = new TreeTransformer;
  17588. merge(Compressor.prototype, {
  17589. option: function(key) { return this.options[key] },
  17590. warn: function() {
  17591. if (this.options.warnings)
  17592. AST_Node.warn.apply(AST_Node, arguments);
  17593. },
  17594. before: function(node, descend, in_list) {
  17595. if (node._squeezed) return node;
  17596. if (node instanceof AST_Scope) {
  17597. node.drop_unused(this);
  17598. node = node.hoist_declarations(this);
  17599. }
  17600. descend(node, this);
  17601. node = node.optimize(this);
  17602. if (node instanceof AST_Scope) {
  17603. // dead code removal might leave further unused declarations.
  17604. // this'll usually save very few bytes, but the performance
  17605. // hit seems negligible so I'll just drop it here.
  17606. // no point to repeat warnings.
  17607. var save_warnings = this.options.warnings;
  17608. this.options.warnings = false;
  17609. node.drop_unused(this);
  17610. this.options.warnings = save_warnings;
  17611. }
  17612. node._squeezed = true;
  17613. return node;
  17614. }
  17615. });
  17616. (function(){
  17617. function OPT(node, optimizer) {
  17618. node.DEFMETHOD("optimize", function(compressor){
  17619. var self = this;
  17620. if (self._optimized) return self;
  17621. var opt = optimizer(self, compressor);
  17622. opt._optimized = true;
  17623. if (opt === self) return opt;
  17624. return opt.transform(compressor);
  17625. });
  17626. };
  17627. OPT(AST_Node, function(self, compressor){
  17628. return self;
  17629. });
  17630. AST_Node.DEFMETHOD("equivalent_to", function(node){
  17631. // XXX: this is a rather expensive way to test two node's equivalence:
  17632. return this.print_to_string() == node.print_to_string();
  17633. });
  17634. function make_node(ctor, orig, props) {
  17635. if (!props) props = {};
  17636. if (orig) {
  17637. if (!props.start) props.start = orig.start;
  17638. if (!props.end) props.end = orig.end;
  17639. }
  17640. return new ctor(props);
  17641. };
  17642. function make_node_from_constant(compressor, val, orig) {
  17643. // XXX: WIP.
  17644. // if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){
  17645. // if (node instanceof AST_SymbolRef) {
  17646. // var scope = compressor.find_parent(AST_Scope);
  17647. // var def = scope.find_variable(node);
  17648. // node.thedef = def;
  17649. // return node;
  17650. // }
  17651. // })).transform(compressor);
  17652. if (val instanceof AST_Node) return val.transform(compressor);
  17653. switch (typeof val) {
  17654. case "string":
  17655. return make_node(AST_String, orig, {
  17656. value: val
  17657. }).optimize(compressor);
  17658. case "number":
  17659. return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
  17660. value: val
  17661. }).optimize(compressor);
  17662. case "boolean":
  17663. return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
  17664. case "undefined":
  17665. return make_node(AST_Undefined, orig).optimize(compressor);
  17666. default:
  17667. if (val === null) {
  17668. return make_node(AST_Null, orig).optimize(compressor);
  17669. }
  17670. if (val instanceof RegExp) {
  17671. return make_node(AST_RegExp, orig).optimize(compressor);
  17672. }
  17673. throw new Error(string_template("Can't handle constant of type: {type}", {
  17674. type: typeof val
  17675. }));
  17676. }
  17677. };
  17678. function as_statement_array(thing) {
  17679. if (thing === null) return [];
  17680. if (thing instanceof AST_BlockStatement) return thing.body;
  17681. if (thing instanceof AST_EmptyStatement) return [];
  17682. if (thing instanceof AST_Statement) return [ thing ];
  17683. throw new Error("Can't convert thing to statement array");
  17684. };
  17685. function is_empty(thing) {
  17686. if (thing === null) return true;
  17687. if (thing instanceof AST_EmptyStatement) return true;
  17688. if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
  17689. return false;
  17690. };
  17691. function loop_body(x) {
  17692. if (x instanceof AST_Switch) return x;
  17693. if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
  17694. return (x.body instanceof AST_BlockStatement ? x.body : x);
  17695. }
  17696. return x;
  17697. };
  17698. function tighten_body(statements, compressor) {
  17699. var CHANGED;
  17700. do {
  17701. CHANGED = false;
  17702. statements = eliminate_spurious_blocks(statements);
  17703. if (compressor.option("dead_code")) {
  17704. statements = eliminate_dead_code(statements, compressor);
  17705. }
  17706. if (compressor.option("if_return")) {
  17707. statements = handle_if_return(statements, compressor);
  17708. }
  17709. if (compressor.option("sequences")) {
  17710. statements = sequencesize(statements, compressor);
  17711. }
  17712. if (compressor.option("join_vars")) {
  17713. statements = join_consecutive_vars(statements, compressor);
  17714. }
  17715. } while (CHANGED);
  17716. if (compressor.option("negate_iife")) {
  17717. negate_iifes(statements, compressor);
  17718. }
  17719. return statements;
  17720. function eliminate_spurious_blocks(statements) {
  17721. var seen_dirs = [];
  17722. return statements.reduce(function(a, stat){
  17723. if (stat instanceof AST_BlockStatement) {
  17724. CHANGED = true;
  17725. a.push.apply(a, eliminate_spurious_blocks(stat.body));
  17726. } else if (stat instanceof AST_EmptyStatement) {
  17727. CHANGED = true;
  17728. } else if (stat instanceof AST_Directive) {
  17729. if (seen_dirs.indexOf(stat.value) < 0) {
  17730. a.push(stat);
  17731. seen_dirs.push(stat.value);
  17732. } else {
  17733. CHANGED = true;
  17734. }
  17735. } else {
  17736. a.push(stat);
  17737. }
  17738. return a;
  17739. }, []);
  17740. };
  17741. function handle_if_return(statements, compressor) {
  17742. var self = compressor.self();
  17743. var in_lambda = self instanceof AST_Lambda;
  17744. var ret = [];
  17745. loop: for (var i = statements.length; --i >= 0;) {
  17746. var stat = statements[i];
  17747. switch (true) {
  17748. case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
  17749. CHANGED = true;
  17750. // note, ret.length is probably always zero
  17751. // because we drop unreachable code before this
  17752. // step. nevertheless, it's good to check.
  17753. continue loop;
  17754. case stat instanceof AST_If:
  17755. if (stat.body instanceof AST_Return) {
  17756. //---
  17757. // pretty silly case, but:
  17758. // if (foo()) return; return; ==> foo(); return;
  17759. if (((in_lambda && ret.length == 0)
  17760. || (ret[0] instanceof AST_Return && !ret[0].value))
  17761. && !stat.body.value && !stat.alternative) {
  17762. CHANGED = true;
  17763. var cond = make_node(AST_SimpleStatement, stat.condition, {
  17764. body: stat.condition
  17765. });
  17766. ret.unshift(cond);
  17767. continue loop;
  17768. }
  17769. //---
  17770. // if (foo()) return x; return y; ==> return foo() ? x : y;
  17771. if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
  17772. CHANGED = true;
  17773. stat = stat.clone();
  17774. stat.alternative = ret[0];
  17775. ret[0] = stat.transform(compressor);
  17776. continue loop;
  17777. }
  17778. //---
  17779. // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
  17780. if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
  17781. CHANGED = true;
  17782. stat = stat.clone();
  17783. stat.alternative = ret[0] || make_node(AST_Return, stat, {
  17784. value: make_node(AST_Undefined, stat)
  17785. });
  17786. ret[0] = stat.transform(compressor);
  17787. continue loop;
  17788. }
  17789. //---
  17790. // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
  17791. if (!stat.body.value && in_lambda) {
  17792. CHANGED = true;
  17793. stat = stat.clone();
  17794. stat.condition = stat.condition.negate(compressor);
  17795. stat.body = make_node(AST_BlockStatement, stat, {
  17796. body: as_statement_array(stat.alternative).concat(ret)
  17797. });
  17798. stat.alternative = null;
  17799. ret = [ stat.transform(compressor) ];
  17800. continue loop;
  17801. }
  17802. //---
  17803. if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
  17804. && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
  17805. CHANGED = true;
  17806. ret.push(make_node(AST_Return, ret[0], {
  17807. value: make_node(AST_Undefined, ret[0])
  17808. }).transform(compressor));
  17809. ret = as_statement_array(stat.alternative).concat(ret);
  17810. ret.unshift(stat);
  17811. continue loop;
  17812. }
  17813. }
  17814. var ab = aborts(stat.body);
  17815. var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
  17816. if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
  17817. || (ab instanceof AST_Continue && self === loop_body(lct))
  17818. || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
  17819. if (ab.label) {
  17820. remove(ab.label.thedef.references, ab.label);
  17821. }
  17822. CHANGED = true;
  17823. var body = as_statement_array(stat.body).slice(0, -1);
  17824. stat = stat.clone();
  17825. stat.condition = stat.condition.negate(compressor);
  17826. stat.body = make_node(AST_BlockStatement, stat, {
  17827. body: ret
  17828. });
  17829. stat.alternative = make_node(AST_BlockStatement, stat, {
  17830. body: body
  17831. });
  17832. ret = [ stat.transform(compressor) ];
  17833. continue loop;
  17834. }
  17835. var ab = aborts(stat.alternative);
  17836. var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
  17837. if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
  17838. || (ab instanceof AST_Continue && self === loop_body(lct))
  17839. || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
  17840. if (ab.label) {
  17841. remove(ab.label.thedef.references, ab.label);
  17842. }
  17843. CHANGED = true;
  17844. stat = stat.clone();
  17845. stat.body = make_node(AST_BlockStatement, stat.body, {
  17846. body: as_statement_array(stat.body).concat(ret)
  17847. });
  17848. stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
  17849. body: as_statement_array(stat.alternative).slice(0, -1)
  17850. });
  17851. ret = [ stat.transform(compressor) ];
  17852. continue loop;
  17853. }
  17854. ret.unshift(stat);
  17855. break;
  17856. default:
  17857. ret.unshift(stat);
  17858. break;
  17859. }
  17860. }
  17861. return ret;
  17862. };
  17863. function eliminate_dead_code(statements, compressor) {
  17864. var has_quit = false;
  17865. var orig = statements.length;
  17866. var self = compressor.self();
  17867. statements = statements.reduce(function(a, stat){
  17868. if (has_quit) {
  17869. extract_declarations_from_unreachable_code(compressor, stat, a);
  17870. } else {
  17871. if (stat instanceof AST_LoopControl) {
  17872. var lct = compressor.loopcontrol_target(stat.label);
  17873. if ((stat instanceof AST_Break
  17874. && lct instanceof AST_BlockStatement
  17875. && loop_body(lct) === self) || (stat instanceof AST_Continue
  17876. && loop_body(lct) === self)) {
  17877. if (stat.label) {
  17878. remove(stat.label.thedef.references, stat.label);
  17879. }
  17880. } else {
  17881. a.push(stat);
  17882. }
  17883. } else {
  17884. a.push(stat);
  17885. }
  17886. if (aborts(stat)) has_quit = true;
  17887. }
  17888. return a;
  17889. }, []);
  17890. CHANGED = statements.length != orig;
  17891. return statements;
  17892. };
  17893. function sequencesize(statements, compressor) {
  17894. if (statements.length < 2) return statements;
  17895. var seq = [], ret = [];
  17896. function push_seq() {
  17897. seq = AST_Seq.from_array(seq);
  17898. if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
  17899. body: seq
  17900. }));
  17901. seq = [];
  17902. };
  17903. statements.forEach(function(stat){
  17904. if (stat instanceof AST_SimpleStatement) seq.push(stat.body);
  17905. else push_seq(), ret.push(stat);
  17906. });
  17907. push_seq();
  17908. ret = sequencesize_2(ret, compressor);
  17909. CHANGED = ret.length != statements.length;
  17910. return ret;
  17911. };
  17912. function sequencesize_2(statements, compressor) {
  17913. function cons_seq(right) {
  17914. ret.pop();
  17915. var left = prev.body;
  17916. if (left instanceof AST_Seq) {
  17917. left.add(right);
  17918. } else {
  17919. left = AST_Seq.cons(left, right);
  17920. }
  17921. return left.transform(compressor);
  17922. };
  17923. var ret = [], prev = null;
  17924. statements.forEach(function(stat){
  17925. if (prev) {
  17926. if (stat instanceof AST_For) {
  17927. var opera = {};
  17928. try {
  17929. prev.body.walk(new TreeWalker(function(node){
  17930. if (node instanceof AST_Binary && node.operator == "in")
  17931. throw opera;
  17932. }));
  17933. if (stat.init && !(stat.init instanceof AST_Definitions)) {
  17934. stat.init = cons_seq(stat.init);
  17935. }
  17936. else if (!stat.init) {
  17937. stat.init = prev.body;
  17938. ret.pop();
  17939. }
  17940. } catch(ex) {
  17941. if (ex !== opera) throw ex;
  17942. }
  17943. }
  17944. else if (stat instanceof AST_If) {
  17945. stat.condition = cons_seq(stat.condition);
  17946. }
  17947. else if (stat instanceof AST_With) {
  17948. stat.expression = cons_seq(stat.expression);
  17949. }
  17950. else if (stat instanceof AST_Exit && stat.value) {
  17951. stat.value = cons_seq(stat.value);
  17952. }
  17953. else if (stat instanceof AST_Exit) {
  17954. stat.value = cons_seq(make_node(AST_Undefined, stat));
  17955. }
  17956. else if (stat instanceof AST_Switch) {
  17957. stat.expression = cons_seq(stat.expression);
  17958. }
  17959. }
  17960. ret.push(stat);
  17961. prev = stat instanceof AST_SimpleStatement ? stat : null;
  17962. });
  17963. return ret;
  17964. };
  17965. function join_consecutive_vars(statements, compressor) {
  17966. var prev = null;
  17967. return statements.reduce(function(a, stat){
  17968. if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
  17969. prev.definitions = prev.definitions.concat(stat.definitions);
  17970. CHANGED = true;
  17971. }
  17972. else if (stat instanceof AST_For
  17973. && prev instanceof AST_Definitions
  17974. && (!stat.init || stat.init.TYPE == prev.TYPE)) {
  17975. CHANGED = true;
  17976. a.pop();
  17977. if (stat.init) {
  17978. stat.init.definitions = prev.definitions.concat(stat.init.definitions);
  17979. } else {
  17980. stat.init = prev;
  17981. }
  17982. a.push(stat);
  17983. prev = stat;
  17984. }
  17985. else {
  17986. prev = stat;
  17987. a.push(stat);
  17988. }
  17989. return a;
  17990. }, []);
  17991. };
  17992. function negate_iifes(statements, compressor) {
  17993. statements.forEach(function(stat){
  17994. if (stat instanceof AST_SimpleStatement) {
  17995. stat.body = (function transform(thing) {
  17996. return thing.transform(new TreeTransformer(function(node){
  17997. if (node instanceof AST_Call && node.expression instanceof AST_Function) {
  17998. return make_node(AST_UnaryPrefix, node, {
  17999. operator: "!",
  18000. expression: node
  18001. });
  18002. }
  18003. else if (node instanceof AST_Call) {
  18004. node.expression = transform(node.expression);
  18005. }
  18006. else if (node instanceof AST_Seq) {
  18007. node.car = transform(node.car);
  18008. }
  18009. else if (node instanceof AST_Conditional) {
  18010. var expr = transform(node.condition);
  18011. if (expr !== node.condition) {
  18012. // it has been negated, reverse
  18013. node.condition = expr;
  18014. var tmp = node.consequent;
  18015. node.consequent = node.alternative;
  18016. node.alternative = tmp;
  18017. }
  18018. }
  18019. return node;
  18020. }));
  18021. })(stat.body);
  18022. }
  18023. });
  18024. };
  18025. };
  18026. function extract_declarations_from_unreachable_code(compressor, stat, target) {
  18027. compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
  18028. stat.walk(new TreeWalker(function(node){
  18029. if (node instanceof AST_Definitions) {
  18030. compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
  18031. node.remove_initializers();
  18032. target.push(node);
  18033. return true;
  18034. }
  18035. if (node instanceof AST_Defun) {
  18036. target.push(node);
  18037. return true;
  18038. }
  18039. if (node instanceof AST_Scope) {
  18040. return true;
  18041. }
  18042. }));
  18043. };
  18044. /* -----[ boolean/negation helpers ]----- */
  18045. // methods to determine whether an expression has a boolean result type
  18046. (function (def){
  18047. var unary_bool = [ "!", "delete" ];
  18048. var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
  18049. def(AST_Node, function(){ return false });
  18050. def(AST_UnaryPrefix, function(){
  18051. return member(this.operator, unary_bool);
  18052. });
  18053. def(AST_Binary, function(){
  18054. return member(this.operator, binary_bool) ||
  18055. ( (this.operator == "&&" || this.operator == "||") &&
  18056. this.left.is_boolean() && this.right.is_boolean() );
  18057. });
  18058. def(AST_Conditional, function(){
  18059. return this.consequent.is_boolean() && this.alternative.is_boolean();
  18060. });
  18061. def(AST_Assign, function(){
  18062. return this.operator == "=" && this.right.is_boolean();
  18063. });
  18064. def(AST_Seq, function(){
  18065. return this.cdr.is_boolean();
  18066. });
  18067. def(AST_True, function(){ return true });
  18068. def(AST_False, function(){ return true });
  18069. })(function(node, func){
  18070. node.DEFMETHOD("is_boolean", func);
  18071. });
  18072. // methods to determine if an expression has a string result type
  18073. (function (def){
  18074. def(AST_Node, function(){ return false });
  18075. def(AST_String, function(){ return true });
  18076. def(AST_UnaryPrefix, function(){
  18077. return this.operator == "typeof";
  18078. });
  18079. def(AST_Binary, function(compressor){
  18080. return this.operator == "+" &&
  18081. (this.left.is_string(compressor) || this.right.is_string(compressor));
  18082. });
  18083. def(AST_Assign, function(compressor){
  18084. return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
  18085. });
  18086. def(AST_Seq, function(compressor){
  18087. return this.cdr.is_string(compressor);
  18088. });
  18089. def(AST_Conditional, function(compressor){
  18090. return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
  18091. });
  18092. def(AST_Call, function(compressor){
  18093. return compressor.option("unsafe")
  18094. && this.expression instanceof AST_SymbolRef
  18095. && this.expression.name == "String"
  18096. && this.expression.undeclared();
  18097. });
  18098. })(function(node, func){
  18099. node.DEFMETHOD("is_string", func);
  18100. });
  18101. function best_of(ast1, ast2) {
  18102. return ast1.print_to_string().length >
  18103. ast2.print_to_string().length
  18104. ? ast2 : ast1;
  18105. };
  18106. // methods to evaluate a constant expression
  18107. (function (def){
  18108. // The evaluate method returns an array with one or two
  18109. // elements. If the node has been successfully reduced to a
  18110. // constant, then the second element tells us the value;
  18111. // otherwise the second element is missing. The first element
  18112. // of the array is always an AST_Node descendant; when
  18113. // evaluation was successful it's a node that represents the
  18114. // constant; otherwise it's the original node.
  18115. AST_Node.DEFMETHOD("evaluate", function(compressor){
  18116. if (!compressor.option("evaluate")) return [ this ];
  18117. try {
  18118. var val = this._eval(), ast = make_node_from_constant(compressor, val, this);
  18119. return [ best_of(ast, this), val ];
  18120. } catch(ex) {
  18121. if (ex !== def) throw ex;
  18122. return [ this ];
  18123. }
  18124. });
  18125. def(AST_Statement, function(){
  18126. throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
  18127. });
  18128. def(AST_Function, function(){
  18129. // XXX: AST_Function inherits from AST_Scope, which itself
  18130. // inherits from AST_Statement; however, an AST_Function
  18131. // isn't really a statement. This could byte in other
  18132. // places too. :-( Wish JS had multiple inheritance.
  18133. throw def;
  18134. });
  18135. function ev(node) {
  18136. return node._eval();
  18137. };
  18138. def(AST_Node, function(){
  18139. throw def; // not constant
  18140. });
  18141. def(AST_Constant, function(){
  18142. return this.getValue();
  18143. });
  18144. def(AST_UnaryPrefix, function(){
  18145. var e = this.expression;
  18146. switch (this.operator) {
  18147. case "!": return !ev(e);
  18148. case "typeof":
  18149. // Function would be evaluated to an array and so typeof would
  18150. // incorrectly return 'object'. Hence making is a special case.
  18151. if (e instanceof AST_Function) return typeof function(){};
  18152. e = ev(e);
  18153. // typeof <RegExp> returns "object" or "function" on different platforms
  18154. // so cannot evaluate reliably
  18155. if (e instanceof RegExp) throw def;
  18156. return typeof e;
  18157. case "void": return void ev(e);
  18158. case "~": return ~ev(e);
  18159. case "-":
  18160. e = ev(e);
  18161. if (e === 0) throw def;
  18162. return -e;
  18163. case "+": return +ev(e);
  18164. }
  18165. throw def;
  18166. });
  18167. def(AST_Binary, function(){
  18168. var left = this.left, right = this.right;
  18169. switch (this.operator) {
  18170. case "&&" : return ev(left) && ev(right);
  18171. case "||" : return ev(left) || ev(right);
  18172. case "|" : return ev(left) | ev(right);
  18173. case "&" : return ev(left) & ev(right);
  18174. case "^" : return ev(left) ^ ev(right);
  18175. case "+" : return ev(left) + ev(right);
  18176. case "*" : return ev(left) * ev(right);
  18177. case "/" : return ev(left) / ev(right);
  18178. case "%" : return ev(left) % ev(right);
  18179. case "-" : return ev(left) - ev(right);
  18180. case "<<" : return ev(left) << ev(right);
  18181. case ">>" : return ev(left) >> ev(right);
  18182. case ">>>" : return ev(left) >>> ev(right);
  18183. case "==" : return ev(left) == ev(right);
  18184. case "===" : return ev(left) === ev(right);
  18185. case "!=" : return ev(left) != ev(right);
  18186. case "!==" : return ev(left) !== ev(right);
  18187. case "<" : return ev(left) < ev(right);
  18188. case "<=" : return ev(left) <= ev(right);
  18189. case ">" : return ev(left) > ev(right);
  18190. case ">=" : return ev(left) >= ev(right);
  18191. case "in" : return ev(left) in ev(right);
  18192. case "instanceof" : return ev(left) instanceof ev(right);
  18193. }
  18194. throw def;
  18195. });
  18196. def(AST_Conditional, function(){
  18197. return ev(this.condition)
  18198. ? ev(this.consequent)
  18199. : ev(this.alternative);
  18200. });
  18201. def(AST_SymbolRef, function(){
  18202. var d = this.definition();
  18203. if (d && d.constant && d.init) return ev(d.init);
  18204. throw def;
  18205. });
  18206. })(function(node, func){
  18207. node.DEFMETHOD("_eval", func);
  18208. });
  18209. // method to negate an expression
  18210. (function(def){
  18211. function basic_negation(exp) {
  18212. return make_node(AST_UnaryPrefix, exp, {
  18213. operator: "!",
  18214. expression: exp
  18215. });
  18216. };
  18217. def(AST_Node, function(){
  18218. return basic_negation(this);
  18219. });
  18220. def(AST_Statement, function(){
  18221. throw new Error("Cannot negate a statement");
  18222. });
  18223. def(AST_Function, function(){
  18224. return basic_negation(this);
  18225. });
  18226. def(AST_UnaryPrefix, function(){
  18227. if (this.operator == "!")
  18228. return this.expression;
  18229. return basic_negation(this);
  18230. });
  18231. def(AST_Seq, function(compressor){
  18232. var self = this.clone();
  18233. self.cdr = self.cdr.negate(compressor);
  18234. return self;
  18235. });
  18236. def(AST_Conditional, function(compressor){
  18237. var self = this.clone();
  18238. self.consequent = self.consequent.negate(compressor);
  18239. self.alternative = self.alternative.negate(compressor);
  18240. return best_of(basic_negation(this), self);
  18241. });
  18242. def(AST_Binary, function(compressor){
  18243. var self = this.clone(), op = this.operator;
  18244. if (compressor.option("unsafe_comps")) {
  18245. switch (op) {
  18246. case "<=" : self.operator = ">" ; return self;
  18247. case "<" : self.operator = ">=" ; return self;
  18248. case ">=" : self.operator = "<" ; return self;
  18249. case ">" : self.operator = "<=" ; return self;
  18250. }
  18251. }
  18252. switch (op) {
  18253. case "==" : self.operator = "!="; return self;
  18254. case "!=" : self.operator = "=="; return self;
  18255. case "===": self.operator = "!=="; return self;
  18256. case "!==": self.operator = "==="; return self;
  18257. case "&&":
  18258. self.operator = "||";
  18259. self.left = self.left.negate(compressor);
  18260. self.right = self.right.negate(compressor);
  18261. return best_of(basic_negation(this), self);
  18262. case "||":
  18263. self.operator = "&&";
  18264. self.left = self.left.negate(compressor);
  18265. self.right = self.right.negate(compressor);
  18266. return best_of(basic_negation(this), self);
  18267. }
  18268. return basic_negation(this);
  18269. });
  18270. })(function(node, func){
  18271. node.DEFMETHOD("negate", function(compressor){
  18272. return func.call(this, compressor);
  18273. });
  18274. });
  18275. // determine if expression has side effects
  18276. (function(def){
  18277. def(AST_Node, function(){ return true });
  18278. def(AST_EmptyStatement, function(){ return false });
  18279. def(AST_Constant, function(){ return false });
  18280. def(AST_This, function(){ return false });
  18281. def(AST_Block, function(){
  18282. for (var i = this.body.length; --i >= 0;) {
  18283. if (this.body[i].has_side_effects())
  18284. return true;
  18285. }
  18286. return false;
  18287. });
  18288. def(AST_SimpleStatement, function(){
  18289. return this.body.has_side_effects();
  18290. });
  18291. def(AST_Defun, function(){ return true });
  18292. def(AST_Function, function(){ return false });
  18293. def(AST_Binary, function(){
  18294. return this.left.has_side_effects()
  18295. || this.right.has_side_effects();
  18296. });
  18297. def(AST_Assign, function(){ return true });
  18298. def(AST_Conditional, function(){
  18299. return this.condition.has_side_effects()
  18300. || this.consequent.has_side_effects()
  18301. || this.alternative.has_side_effects();
  18302. });
  18303. def(AST_Unary, function(){
  18304. return this.operator == "delete"
  18305. || this.operator == "++"
  18306. || this.operator == "--"
  18307. || this.expression.has_side_effects();
  18308. });
  18309. def(AST_SymbolRef, function(){ return false });
  18310. def(AST_Object, function(){
  18311. for (var i = this.properties.length; --i >= 0;)
  18312. if (this.properties[i].has_side_effects())
  18313. return true;
  18314. return false;
  18315. });
  18316. def(AST_ObjectProperty, function(){
  18317. return this.value.has_side_effects();
  18318. });
  18319. def(AST_Array, function(){
  18320. for (var i = this.elements.length; --i >= 0;)
  18321. if (this.elements[i].has_side_effects())
  18322. return true;
  18323. return false;
  18324. });
  18325. // def(AST_Dot, function(){
  18326. // return this.expression.has_side_effects();
  18327. // });
  18328. // def(AST_Sub, function(){
  18329. // return this.expression.has_side_effects()
  18330. // || this.property.has_side_effects();
  18331. // });
  18332. def(AST_PropAccess, function(){
  18333. return true;
  18334. });
  18335. def(AST_Seq, function(){
  18336. return this.car.has_side_effects()
  18337. || this.cdr.has_side_effects();
  18338. });
  18339. })(function(node, func){
  18340. node.DEFMETHOD("has_side_effects", func);
  18341. });
  18342. // tell me if a statement aborts
  18343. function aborts(thing) {
  18344. return thing && thing.aborts();
  18345. };
  18346. (function(def){
  18347. def(AST_Statement, function(){ return null });
  18348. def(AST_Jump, function(){ return this });
  18349. function block_aborts(){
  18350. var n = this.body.length;
  18351. return n > 0 && aborts(this.body[n - 1]);
  18352. };
  18353. def(AST_BlockStatement, block_aborts);
  18354. def(AST_SwitchBranch, block_aborts);
  18355. def(AST_If, function(){
  18356. return this.alternative && aborts(this.body) && aborts(this.alternative);
  18357. });
  18358. })(function(node, func){
  18359. node.DEFMETHOD("aborts", func);
  18360. });
  18361. /* -----[ optimizers ]----- */
  18362. OPT(AST_Directive, function(self, compressor){
  18363. if (self.scope.has_directive(self.value) !== self.scope) {
  18364. return make_node(AST_EmptyStatement, self);
  18365. }
  18366. return self;
  18367. });
  18368. OPT(AST_Debugger, function(self, compressor){
  18369. if (compressor.option("drop_debugger"))
  18370. return make_node(AST_EmptyStatement, self);
  18371. return self;
  18372. });
  18373. OPT(AST_LabeledStatement, function(self, compressor){
  18374. if (self.body instanceof AST_Break
  18375. && compressor.loopcontrol_target(self.body.label) === self.body) {
  18376. return make_node(AST_EmptyStatement, self);
  18377. }
  18378. return self.label.references.length == 0 ? self.body : self;
  18379. });
  18380. OPT(AST_Block, function(self, compressor){
  18381. self.body = tighten_body(self.body, compressor);
  18382. return self;
  18383. });
  18384. OPT(AST_BlockStatement, function(self, compressor){
  18385. self.body = tighten_body(self.body, compressor);
  18386. switch (self.body.length) {
  18387. case 1: return self.body[0];
  18388. case 0: return make_node(AST_EmptyStatement, self);
  18389. }
  18390. return self;
  18391. });
  18392. AST_Scope.DEFMETHOD("drop_unused", function(compressor){
  18393. var self = this;
  18394. if (compressor.option("unused")
  18395. && !(self instanceof AST_Toplevel)
  18396. && !self.uses_eval
  18397. ) {
  18398. var in_use = [];
  18399. var initializations = new Dictionary();
  18400. // pass 1: find out which symbols are directly used in
  18401. // this scope (not in nested scopes).
  18402. var scope = this;
  18403. var tw = new TreeWalker(function(node, descend){
  18404. if (node !== self) {
  18405. if (node instanceof AST_Defun) {
  18406. initializations.add(node.name.name, node);
  18407. return true; // don't go in nested scopes
  18408. }
  18409. if (node instanceof AST_Definitions && scope === self) {
  18410. node.definitions.forEach(function(def){
  18411. if (def.value) {
  18412. initializations.add(def.name.name, def.value);
  18413. if (def.value.has_side_effects()) {
  18414. def.value.walk(tw);
  18415. }
  18416. }
  18417. });
  18418. return true;
  18419. }
  18420. if (node instanceof AST_SymbolRef) {
  18421. push_uniq(in_use, node.definition());
  18422. return true;
  18423. }
  18424. if (node instanceof AST_Scope) {
  18425. var save_scope = scope;
  18426. scope = node;
  18427. descend();
  18428. scope = save_scope;
  18429. return true;
  18430. }
  18431. }
  18432. });
  18433. self.walk(tw);
  18434. // pass 2: for every used symbol we need to walk its
  18435. // initialization code to figure out if it uses other
  18436. // symbols (that may not be in_use).
  18437. for (var i = 0; i < in_use.length; ++i) {
  18438. in_use[i].orig.forEach(function(decl){
  18439. // undeclared globals will be instanceof AST_SymbolRef
  18440. var init = initializations.get(decl.name);
  18441. if (init) init.forEach(function(init){
  18442. var tw = new TreeWalker(function(node){
  18443. if (node instanceof AST_SymbolRef) {
  18444. push_uniq(in_use, node.definition());
  18445. }
  18446. });
  18447. init.walk(tw);
  18448. });
  18449. });
  18450. }
  18451. // pass 3: we should drop declarations not in_use
  18452. var tt = new TreeTransformer(
  18453. function before(node, descend, in_list) {
  18454. if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
  18455. for (var a = node.argnames, i = a.length; --i >= 0;) {
  18456. var sym = a[i];
  18457. if (sym.unreferenced()) {
  18458. a.pop();
  18459. compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
  18460. name : sym.name,
  18461. file : sym.start.file,
  18462. line : sym.start.line,
  18463. col : sym.start.col
  18464. });
  18465. }
  18466. else break;
  18467. }
  18468. }
  18469. if (node instanceof AST_Defun && node !== self) {
  18470. if (!member(node.name.definition(), in_use)) {
  18471. compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
  18472. name : node.name.name,
  18473. file : node.name.start.file,
  18474. line : node.name.start.line,
  18475. col : node.name.start.col
  18476. });
  18477. return make_node(AST_EmptyStatement, node);
  18478. }
  18479. return node;
  18480. }
  18481. if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
  18482. var def = node.definitions.filter(function(def){
  18483. if (member(def.name.definition(), in_use)) return true;
  18484. var w = {
  18485. name : def.name.name,
  18486. file : def.name.start.file,
  18487. line : def.name.start.line,
  18488. col : def.name.start.col
  18489. };
  18490. if (def.value && def.value.has_side_effects()) {
  18491. def._unused_side_effects = true;
  18492. compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
  18493. return true;
  18494. }
  18495. compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);
  18496. return false;
  18497. });
  18498. // place uninitialized names at the start
  18499. def = mergeSort(def, function(a, b){
  18500. if (!a.value && b.value) return -1;
  18501. if (!b.value && a.value) return 1;
  18502. return 0;
  18503. });
  18504. // for unused names whose initialization has
  18505. // side effects, we can cascade the init. code
  18506. // into the next one, or next statement.
  18507. var side_effects = [];
  18508. for (var i = 0; i < def.length;) {
  18509. var x = def[i];
  18510. if (x._unused_side_effects) {
  18511. side_effects.push(x.value);
  18512. def.splice(i, 1);
  18513. } else {
  18514. if (side_effects.length > 0) {
  18515. side_effects.push(x.value);
  18516. x.value = AST_Seq.from_array(side_effects);
  18517. side_effects = [];
  18518. }
  18519. ++i;
  18520. }
  18521. }
  18522. if (side_effects.length > 0) {
  18523. side_effects = make_node(AST_BlockStatement, node, {
  18524. body: [ make_node(AST_SimpleStatement, node, {
  18525. body: AST_Seq.from_array(side_effects)
  18526. }) ]
  18527. });
  18528. } else {
  18529. side_effects = null;
  18530. }
  18531. if (def.length == 0 && !side_effects) {
  18532. return make_node(AST_EmptyStatement, node);
  18533. }
  18534. if (def.length == 0) {
  18535. return side_effects;
  18536. }
  18537. node.definitions = def;
  18538. if (side_effects) {
  18539. side_effects.body.unshift(node);
  18540. node = side_effects;
  18541. }
  18542. return node;
  18543. }
  18544. if (node instanceof AST_For && node.init instanceof AST_BlockStatement) {
  18545. descend(node, this);
  18546. // certain combination of unused name + side effect leads to:
  18547. // https://github.com/mishoo/UglifyJS2/issues/44
  18548. // that's an invalid AST.
  18549. // We fix it at this stage by moving the `var` outside the `for`.
  18550. var body = node.init.body.slice(0, -1);
  18551. node.init = node.init.body.slice(-1)[0].body;
  18552. body.push(node);
  18553. return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
  18554. body: body
  18555. });
  18556. }
  18557. if (node instanceof AST_Scope && node !== self)
  18558. return node;
  18559. }
  18560. );
  18561. self.transform(tt);
  18562. }
  18563. });
  18564. AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
  18565. var hoist_funs = compressor.option("hoist_funs");
  18566. var hoist_vars = compressor.option("hoist_vars");
  18567. var self = this;
  18568. if (hoist_funs || hoist_vars) {
  18569. var dirs = [];
  18570. var hoisted = [];
  18571. var vars = new Dictionary(), vars_found = 0, var_decl = 0;
  18572. // let's count var_decl first, we seem to waste a lot of
  18573. // space if we hoist `var` when there's only one.
  18574. self.walk(new TreeWalker(function(node){
  18575. if (node instanceof AST_Scope && node !== self)
  18576. return true;
  18577. if (node instanceof AST_Var) {
  18578. ++var_decl;
  18579. return true;
  18580. }
  18581. }));
  18582. hoist_vars = hoist_vars && var_decl > 1;
  18583. var tt = new TreeTransformer(
  18584. function before(node) {
  18585. if (node !== self) {
  18586. if (node instanceof AST_Directive) {
  18587. dirs.push(node);
  18588. return make_node(AST_EmptyStatement, node);
  18589. }
  18590. if (node instanceof AST_Defun && hoist_funs) {
  18591. hoisted.push(node);
  18592. return make_node(AST_EmptyStatement, node);
  18593. }
  18594. if (node instanceof AST_Var && hoist_vars) {
  18595. node.definitions.forEach(function(def){
  18596. vars.set(def.name.name, def);
  18597. ++vars_found;
  18598. });
  18599. var seq = node.to_assignments();
  18600. var p = tt.parent();
  18601. if (p instanceof AST_ForIn && p.init === node) {
  18602. if (seq == null) return node.definitions[0].name;
  18603. return seq;
  18604. }
  18605. if (p instanceof AST_For && p.init === node) {
  18606. return seq;
  18607. }
  18608. if (!seq) return make_node(AST_EmptyStatement, node);
  18609. return make_node(AST_SimpleStatement, node, {
  18610. body: seq
  18611. });
  18612. }
  18613. if (node instanceof AST_Scope)
  18614. return node; // to avoid descending in nested scopes
  18615. }
  18616. }
  18617. );
  18618. self = self.transform(tt);
  18619. if (vars_found > 0) {
  18620. // collect only vars which don't show up in self's arguments list
  18621. var defs = [];
  18622. vars.each(function(def, name){
  18623. if (self instanceof AST_Lambda
  18624. && find_if(function(x){ return x.name == def.name.name },
  18625. self.argnames)) {
  18626. vars.del(name);
  18627. } else {
  18628. def = def.clone();
  18629. def.value = null;
  18630. defs.push(def);
  18631. vars.set(name, def);
  18632. }
  18633. });
  18634. if (defs.length > 0) {
  18635. // try to merge in assignments
  18636. for (var i = 0; i < self.body.length;) {
  18637. if (self.body[i] instanceof AST_SimpleStatement) {
  18638. var expr = self.body[i].body, sym, assign;
  18639. if (expr instanceof AST_Assign
  18640. && expr.operator == "="
  18641. && (sym = expr.left) instanceof AST_Symbol
  18642. && vars.has(sym.name))
  18643. {
  18644. var def = vars.get(sym.name);
  18645. if (def.value) break;
  18646. def.value = expr.right;
  18647. remove(defs, def);
  18648. defs.push(def);
  18649. self.body.splice(i, 1);
  18650. continue;
  18651. }
  18652. if (expr instanceof AST_Seq
  18653. && (assign = expr.car) instanceof AST_Assign
  18654. && assign.operator == "="
  18655. && (sym = assign.left) instanceof AST_Symbol
  18656. && vars.has(sym.name))
  18657. {
  18658. var def = vars.get(sym.name);
  18659. if (def.value) break;
  18660. def.value = assign.right;
  18661. remove(defs, def);
  18662. defs.push(def);
  18663. self.body[i].body = expr.cdr;
  18664. continue;
  18665. }
  18666. }
  18667. if (self.body[i] instanceof AST_EmptyStatement) {
  18668. self.body.splice(i, 1);
  18669. continue;
  18670. }
  18671. if (self.body[i] instanceof AST_BlockStatement) {
  18672. var tmp = [ i, 1 ].concat(self.body[i].body);
  18673. self.body.splice.apply(self.body, tmp);
  18674. continue;
  18675. }
  18676. break;
  18677. }
  18678. defs = make_node(AST_Var, self, {
  18679. definitions: defs
  18680. });
  18681. hoisted.push(defs);
  18682. };
  18683. }
  18684. self.body = dirs.concat(hoisted, self.body);
  18685. }
  18686. return self;
  18687. });
  18688. OPT(AST_SimpleStatement, function(self, compressor){
  18689. if (compressor.option("side_effects")) {
  18690. if (!self.body.has_side_effects()) {
  18691. compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
  18692. return make_node(AST_EmptyStatement, self);
  18693. }
  18694. }
  18695. return self;
  18696. });
  18697. OPT(AST_DWLoop, function(self, compressor){
  18698. var cond = self.condition.evaluate(compressor);
  18699. self.condition = cond[0];
  18700. if (!compressor.option("loops")) return self;
  18701. if (cond.length > 1) {
  18702. if (cond[1]) {
  18703. return make_node(AST_For, self, {
  18704. body: self.body
  18705. });
  18706. } else if (self instanceof AST_While) {
  18707. if (compressor.option("dead_code")) {
  18708. var a = [];
  18709. extract_declarations_from_unreachable_code(compressor, self.body, a);
  18710. return make_node(AST_BlockStatement, self, { body: a });
  18711. }
  18712. }
  18713. }
  18714. return self;
  18715. });
  18716. function if_break_in_loop(self, compressor) {
  18717. function drop_it(rest) {
  18718. rest = as_statement_array(rest);
  18719. if (self.body instanceof AST_BlockStatement) {
  18720. self.body = self.body.clone();
  18721. self.body.body = rest.concat(self.body.body.slice(1));
  18722. self.body = self.body.transform(compressor);
  18723. } else {
  18724. self.body = make_node(AST_BlockStatement, self.body, {
  18725. body: rest
  18726. }).transform(compressor);
  18727. }
  18728. if_break_in_loop(self, compressor);
  18729. }
  18730. var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
  18731. if (first instanceof AST_If) {
  18732. if (first.body instanceof AST_Break
  18733. && compressor.loopcontrol_target(first.body.label) === self) {
  18734. if (self.condition) {
  18735. self.condition = make_node(AST_Binary, self.condition, {
  18736. left: self.condition,
  18737. operator: "&&",
  18738. right: first.condition.negate(compressor),
  18739. });
  18740. } else {
  18741. self.condition = first.condition.negate(compressor);
  18742. }
  18743. drop_it(first.alternative);
  18744. }
  18745. else if (first.alternative instanceof AST_Break
  18746. && compressor.loopcontrol_target(first.alternative.label) === self) {
  18747. if (self.condition) {
  18748. self.condition = make_node(AST_Binary, self.condition, {
  18749. left: self.condition,
  18750. operator: "&&",
  18751. right: first.condition,
  18752. });
  18753. } else {
  18754. self.condition = first.condition;
  18755. }
  18756. drop_it(first.body);
  18757. }
  18758. }
  18759. };
  18760. OPT(AST_While, function(self, compressor) {
  18761. if (!compressor.option("loops")) return self;
  18762. self = AST_DWLoop.prototype.optimize.call(self, compressor);
  18763. if (self instanceof AST_While) {
  18764. if_break_in_loop(self, compressor);
  18765. self = make_node(AST_For, self, self).transform(compressor);
  18766. }
  18767. return self;
  18768. });
  18769. OPT(AST_For, function(self, compressor){
  18770. var cond = self.condition;
  18771. if (cond) {
  18772. cond = cond.evaluate(compressor);
  18773. self.condition = cond[0];
  18774. }
  18775. if (!compressor.option("loops")) return self;
  18776. if (cond) {
  18777. if (cond.length > 1 && !cond[1]) {
  18778. if (compressor.option("dead_code")) {
  18779. var a = [];
  18780. if (self.init instanceof AST_Statement) {
  18781. a.push(self.init);
  18782. }
  18783. else if (self.init) {
  18784. a.push(make_node(AST_SimpleStatement, self.init, {
  18785. body: self.init
  18786. }));
  18787. }
  18788. extract_declarations_from_unreachable_code(compressor, self.body, a);
  18789. return make_node(AST_BlockStatement, self, { body: a });
  18790. }
  18791. }
  18792. }
  18793. if_break_in_loop(self, compressor);
  18794. return self;
  18795. });
  18796. OPT(AST_If, function(self, compressor){
  18797. if (!compressor.option("conditionals")) return self;
  18798. // if condition can be statically determined, warn and drop
  18799. // one of the blocks. note, statically determined implies
  18800. // “has no side effects”; also it doesn't work for cases like
  18801. // `x && true`, though it probably should.
  18802. var cond = self.condition.evaluate(compressor);
  18803. self.condition = cond[0];
  18804. if (cond.length > 1) {
  18805. if (cond[1]) {
  18806. compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
  18807. if (compressor.option("dead_code")) {
  18808. var a = [];
  18809. if (self.alternative) {
  18810. extract_declarations_from_unreachable_code(compressor, self.alternative, a);
  18811. }
  18812. a.push(self.body);
  18813. return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
  18814. }
  18815. } else {
  18816. compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
  18817. if (compressor.option("dead_code")) {
  18818. var a = [];
  18819. extract_declarations_from_unreachable_code(compressor, self.body, a);
  18820. if (self.alternative) a.push(self.alternative);
  18821. return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
  18822. }
  18823. }
  18824. }
  18825. if (is_empty(self.alternative)) self.alternative = null;
  18826. var negated = self.condition.negate(compressor);
  18827. var negated_is_best = best_of(self.condition, negated) === negated;
  18828. if (self.alternative && negated_is_best) {
  18829. negated_is_best = false; // because we already do the switch here.
  18830. self.condition = negated;
  18831. var tmp = self.body;
  18832. self.body = self.alternative || make_node(AST_EmptyStatement);
  18833. self.alternative = tmp;
  18834. }
  18835. if (is_empty(self.body) && is_empty(self.alternative)) {
  18836. return make_node(AST_SimpleStatement, self.condition, {
  18837. body: self.condition
  18838. }).transform(compressor);
  18839. }
  18840. if (self.body instanceof AST_SimpleStatement
  18841. && self.alternative instanceof AST_SimpleStatement) {
  18842. return make_node(AST_SimpleStatement, self, {
  18843. body: make_node(AST_Conditional, self, {
  18844. condition : self.condition,
  18845. consequent : self.body.body,
  18846. alternative : self.alternative.body
  18847. })
  18848. }).transform(compressor);
  18849. }
  18850. if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
  18851. if (negated_is_best) return make_node(AST_SimpleStatement, self, {
  18852. body: make_node(AST_Binary, self, {
  18853. operator : "||",
  18854. left : negated,
  18855. right : self.body.body
  18856. })
  18857. }).transform(compressor);
  18858. return make_node(AST_SimpleStatement, self, {
  18859. body: make_node(AST_Binary, self, {
  18860. operator : "&&",
  18861. left : self.condition,
  18862. right : self.body.body
  18863. })
  18864. }).transform(compressor);
  18865. }
  18866. if (self.body instanceof AST_EmptyStatement
  18867. && self.alternative
  18868. && self.alternative instanceof AST_SimpleStatement) {
  18869. return make_node(AST_SimpleStatement, self, {
  18870. body: make_node(AST_Binary, self, {
  18871. operator : "||",
  18872. left : self.condition,
  18873. right : self.alternative.body
  18874. })
  18875. }).transform(compressor);
  18876. }
  18877. if (self.body instanceof AST_Exit
  18878. && self.alternative instanceof AST_Exit
  18879. && self.body.TYPE == self.alternative.TYPE) {
  18880. return make_node(self.body.CTOR, self, {
  18881. value: make_node(AST_Conditional, self, {
  18882. condition : self.condition,
  18883. consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
  18884. alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
  18885. })
  18886. }).transform(compressor);
  18887. }
  18888. if (self.body instanceof AST_If
  18889. && !self.body.alternative
  18890. && !self.alternative) {
  18891. self.condition = make_node(AST_Binary, self.condition, {
  18892. operator: "&&",
  18893. left: self.condition,
  18894. right: self.body.condition
  18895. }).transform(compressor);
  18896. self.body = self.body.body;
  18897. }
  18898. if (aborts(self.body)) {
  18899. if (self.alternative) {
  18900. var alt = self.alternative;
  18901. self.alternative = null;
  18902. return make_node(AST_BlockStatement, self, {
  18903. body: [ self, alt ]
  18904. }).transform(compressor);
  18905. }
  18906. }
  18907. if (aborts(self.alternative)) {
  18908. var body = self.body;
  18909. self.body = self.alternative;
  18910. self.condition = negated_is_best ? negated : self.condition.negate(compressor);
  18911. self.alternative = null;
  18912. return make_node(AST_BlockStatement, self, {
  18913. body: [ self, body ]
  18914. }).transform(compressor);
  18915. }
  18916. return self;
  18917. });
  18918. OPT(AST_Switch, function(self, compressor){
  18919. if (self.body.length == 0 && compressor.option("conditionals")) {
  18920. return make_node(AST_SimpleStatement, self, {
  18921. body: self.expression
  18922. }).transform(compressor);
  18923. }
  18924. for(;;) {
  18925. var last_branch = self.body[self.body.length - 1];
  18926. if (last_branch) {
  18927. var stat = last_branch.body[last_branch.body.length - 1]; // last statement
  18928. if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
  18929. last_branch.body.pop();
  18930. if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
  18931. self.body.pop();
  18932. continue;
  18933. }
  18934. }
  18935. break;
  18936. }
  18937. var exp = self.expression.evaluate(compressor);
  18938. out: if (exp.length == 2) try {
  18939. // constant expression
  18940. self.expression = exp[0];
  18941. if (!compressor.option("dead_code")) break out;
  18942. var value = exp[1];
  18943. var in_if = false;
  18944. var in_block = false;
  18945. var started = false;
  18946. var stopped = false;
  18947. var ruined = false;
  18948. var tt = new TreeTransformer(function(node, descend, in_list){
  18949. if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
  18950. // no need to descend these node types
  18951. return node;
  18952. }
  18953. else if (node instanceof AST_Switch && node === self) {
  18954. node = node.clone();
  18955. descend(node, this);
  18956. return ruined ? node : make_node(AST_BlockStatement, node, {
  18957. body: node.body.reduce(function(a, branch){
  18958. return a.concat(branch.body);
  18959. }, [])
  18960. }).transform(compressor);
  18961. }
  18962. else if (node instanceof AST_If || node instanceof AST_Try) {
  18963. var save = in_if;
  18964. in_if = !in_block;
  18965. descend(node, this);
  18966. in_if = save;
  18967. return node;
  18968. }
  18969. else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
  18970. var save = in_block;
  18971. in_block = true;
  18972. descend(node, this);
  18973. in_block = save;
  18974. return node;
  18975. }
  18976. else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
  18977. if (in_if) {
  18978. ruined = true;
  18979. return node;
  18980. }
  18981. if (in_block) return node;
  18982. stopped = true;
  18983. return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
  18984. }
  18985. else if (node instanceof AST_SwitchBranch && this.parent() === self) {
  18986. if (stopped) return MAP.skip;
  18987. if (node instanceof AST_Case) {
  18988. var exp = node.expression.evaluate(compressor);
  18989. if (exp.length < 2) {
  18990. // got a case with non-constant expression, baling out
  18991. throw self;
  18992. }
  18993. if (exp[1] === value || started) {
  18994. started = true;
  18995. if (aborts(node)) stopped = true;
  18996. descend(node, this);
  18997. return node;
  18998. }
  18999. return MAP.skip;
  19000. }
  19001. descend(node, this);
  19002. return node;
  19003. }
  19004. });
  19005. tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
  19006. self = self.transform(tt);
  19007. } catch(ex) {
  19008. if (ex !== self) throw ex;
  19009. }
  19010. return self;
  19011. });
  19012. OPT(AST_Case, function(self, compressor){
  19013. self.body = tighten_body(self.body, compressor);
  19014. return self;
  19015. });
  19016. OPT(AST_Try, function(self, compressor){
  19017. self.body = tighten_body(self.body, compressor);
  19018. return self;
  19019. });
  19020. AST_Definitions.DEFMETHOD("remove_initializers", function(){
  19021. this.definitions.forEach(function(def){ def.value = null });
  19022. });
  19023. AST_Definitions.DEFMETHOD("to_assignments", function(){
  19024. var assignments = this.definitions.reduce(function(a, def){
  19025. if (def.value) {
  19026. var name = make_node(AST_SymbolRef, def.name, def.name);
  19027. a.push(make_node(AST_Assign, def, {
  19028. operator : "=",
  19029. left : name,
  19030. right : def.value
  19031. }));
  19032. }
  19033. return a;
  19034. }, []);
  19035. if (assignments.length == 0) return null;
  19036. return AST_Seq.from_array(assignments);
  19037. });
  19038. OPT(AST_Definitions, function(self, compressor){
  19039. if (self.definitions.length == 0)
  19040. return make_node(AST_EmptyStatement, self);
  19041. return self;
  19042. });
  19043. OPT(AST_Function, function(self, compressor){
  19044. self = AST_Lambda.prototype.optimize.call(self, compressor);
  19045. if (compressor.option("unused")) {
  19046. if (self.name && self.name.unreferenced()) {
  19047. self.name = null;
  19048. }
  19049. }
  19050. return self;
  19051. });
  19052. OPT(AST_Call, function(self, compressor){
  19053. if (compressor.option("unsafe")) {
  19054. var exp = self.expression;
  19055. if (exp instanceof AST_SymbolRef && exp.undeclared()) {
  19056. switch (exp.name) {
  19057. case "Array":
  19058. if (self.args.length != 1) {
  19059. return make_node(AST_Array, self, {
  19060. elements: self.args
  19061. });
  19062. }
  19063. break;
  19064. case "Object":
  19065. if (self.args.length == 0) {
  19066. return make_node(AST_Object, self, {
  19067. properties: []
  19068. });
  19069. }
  19070. break;
  19071. case "String":
  19072. if (self.args.length == 0) return make_node(AST_String, self, {
  19073. value: ""
  19074. });
  19075. return make_node(AST_Binary, self, {
  19076. left: self.args[0],
  19077. operator: "+",
  19078. right: make_node(AST_String, self, { value: "" })
  19079. });
  19080. case "Function":
  19081. if (all(self.args, function(x){ return x instanceof AST_String })) {
  19082. // quite a corner-case, but we can handle it:
  19083. // https://github.com/mishoo/UglifyJS2/issues/203
  19084. // if the code argument is a constant, then we can minify it.
  19085. try {
  19086. var code = "(function(" + self.args.slice(0, -1).map(function(arg){
  19087. return arg.value;
  19088. }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
  19089. var ast = parse(code);
  19090. ast.figure_out_scope();
  19091. var comp = new Compressor(compressor.options);
  19092. ast = ast.transform(comp);
  19093. ast.figure_out_scope();
  19094. ast.mangle_names();
  19095. var fun = ast.body[0].body.expression;
  19096. var args = fun.argnames.map(function(arg, i){
  19097. return make_node(AST_String, self.args[i], {
  19098. value: arg.print_to_string()
  19099. });
  19100. });
  19101. var code = OutputStream();
  19102. AST_BlockStatement.prototype._codegen.call(fun, fun, code);
  19103. code = code.toString().replace(/^\{|\}$/g, "");
  19104. args.push(make_node(AST_String, self.args[self.args.length - 1], {
  19105. value: code
  19106. }));
  19107. self.args = args;
  19108. return self;
  19109. } catch(ex) {
  19110. if (ex instanceof JS_Parse_Error) {
  19111. compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
  19112. compressor.warn(ex.toString());
  19113. } else {
  19114. console.log(ex);
  19115. }
  19116. }
  19117. }
  19118. break;
  19119. }
  19120. }
  19121. else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
  19122. return make_node(AST_Binary, self, {
  19123. left: make_node(AST_String, self, { value: "" }),
  19124. operator: "+",
  19125. right: exp.expression
  19126. }).transform(compressor);
  19127. }
  19128. }
  19129. if (compressor.option("side_effects")) {
  19130. if (self.expression instanceof AST_Function
  19131. && self.args.length == 0
  19132. && !AST_Block.prototype.has_side_effects.call(self.expression)) {
  19133. return make_node(AST_Undefined, self).transform(compressor);
  19134. }
  19135. }
  19136. return self;
  19137. });
  19138. OPT(AST_New, function(self, compressor){
  19139. if (compressor.option("unsafe")) {
  19140. var exp = self.expression;
  19141. if (exp instanceof AST_SymbolRef && exp.undeclared()) {
  19142. switch (exp.name) {
  19143. case "Object":
  19144. case "RegExp":
  19145. case "Function":
  19146. case "Error":
  19147. case "Array":
  19148. return make_node(AST_Call, self, self).transform(compressor);
  19149. }
  19150. }
  19151. }
  19152. return self;
  19153. });
  19154. OPT(AST_Seq, function(self, compressor){
  19155. if (!compressor.option("side_effects"))
  19156. return self;
  19157. if (!self.car.has_side_effects()) {
  19158. // we shouldn't compress (1,eval)(something) to
  19159. // eval(something) because that changes the meaning of
  19160. // eval (becomes lexical instead of global).
  19161. var p;
  19162. if (!(self.cdr instanceof AST_SymbolRef
  19163. && self.cdr.name == "eval"
  19164. && self.cdr.undeclared()
  19165. && (p = compressor.parent()) instanceof AST_Call
  19166. && p.expression === self)) {
  19167. return self.cdr;
  19168. }
  19169. }
  19170. if (compressor.option("cascade")) {
  19171. if (self.car instanceof AST_Assign
  19172. && !self.car.left.has_side_effects()
  19173. && self.car.left.equivalent_to(self.cdr)) {
  19174. return self.car;
  19175. }
  19176. if (!self.car.has_side_effects()
  19177. && !self.cdr.has_side_effects()
  19178. && self.car.equivalent_to(self.cdr)) {
  19179. return self.car;
  19180. }
  19181. }
  19182. return self;
  19183. });
  19184. AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
  19185. if (compressor.option("sequences")) {
  19186. if (this.expression instanceof AST_Seq) {
  19187. var seq = this.expression;
  19188. var x = seq.to_array();
  19189. this.expression = x.pop();
  19190. x.push(this);
  19191. seq = AST_Seq.from_array(x).transform(compressor);
  19192. return seq;
  19193. }
  19194. }
  19195. return this;
  19196. });
  19197. OPT(AST_UnaryPostfix, function(self, compressor){
  19198. return self.lift_sequences(compressor);
  19199. });
  19200. OPT(AST_UnaryPrefix, function(self, compressor){
  19201. self = self.lift_sequences(compressor);
  19202. var e = self.expression;
  19203. if (compressor.option("booleans") && compressor.in_boolean_context()) {
  19204. switch (self.operator) {
  19205. case "!":
  19206. if (e instanceof AST_UnaryPrefix && e.operator == "!") {
  19207. // !!foo ==> foo, if we're in boolean context
  19208. return e.expression;
  19209. }
  19210. break;
  19211. case "typeof":
  19212. // typeof always returns a non-empty string, thus it's
  19213. // always true in booleans
  19214. compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
  19215. return make_node(AST_True, self);
  19216. }
  19217. if (e instanceof AST_Binary && self.operator == "!") {
  19218. self = best_of(self, e.negate(compressor));
  19219. }
  19220. }
  19221. return self.evaluate(compressor)[0];
  19222. });
  19223. AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
  19224. if (compressor.option("sequences")) {
  19225. if (this.left instanceof AST_Seq) {
  19226. var seq = this.left;
  19227. var x = seq.to_array();
  19228. this.left = x.pop();
  19229. x.push(this);
  19230. seq = AST_Seq.from_array(x).transform(compressor);
  19231. return seq;
  19232. }
  19233. if (this.right instanceof AST_Seq
  19234. && !(this.operator == "||" || this.operator == "&&")
  19235. && !this.left.has_side_effects()) {
  19236. var seq = this.right;
  19237. var x = seq.to_array();
  19238. this.right = x.pop();
  19239. x.push(this);
  19240. seq = AST_Seq.from_array(x).transform(compressor);
  19241. return seq;
  19242. }
  19243. }
  19244. return this;
  19245. });
  19246. var commutativeOperators = makePredicate("== === != !== * & | ^");
  19247. OPT(AST_Binary, function(self, compressor){
  19248. var reverse = compressor.has_directive("use asm") ? noop
  19249. : function(op, force) {
  19250. if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) {
  19251. if (op) self.operator = op;
  19252. var tmp = self.left;
  19253. self.left = self.right;
  19254. self.right = tmp;
  19255. }
  19256. };
  19257. if (commutativeOperators(self.operator)) {
  19258. if (self.right instanceof AST_Constant
  19259. && !(self.left instanceof AST_Constant)) {
  19260. // if right is a constant, whatever side effects the
  19261. // left side might have could not influence the
  19262. // result. hence, force switch.
  19263. reverse(null, true);
  19264. }
  19265. }
  19266. self = self.lift_sequences(compressor);
  19267. if (compressor.option("comparisons")) switch (self.operator) {
  19268. case "===":
  19269. case "!==":
  19270. if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
  19271. (self.left.is_boolean() && self.right.is_boolean())) {
  19272. self.operator = self.operator.substr(0, 2);
  19273. }
  19274. // XXX: intentionally falling down to the next case
  19275. case "==":
  19276. case "!=":
  19277. if (self.left instanceof AST_String
  19278. && self.left.value == "undefined"
  19279. && self.right instanceof AST_UnaryPrefix
  19280. && self.right.operator == "typeof"
  19281. && compressor.option("unsafe")) {
  19282. if (!(self.right.expression instanceof AST_SymbolRef)
  19283. || !self.right.expression.undeclared()) {
  19284. self.right = self.right.expression;
  19285. self.left = make_node(AST_Undefined, self.left).optimize(compressor);
  19286. if (self.operator.length == 2) self.operator += "=";
  19287. }
  19288. }
  19289. break;
  19290. }
  19291. if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
  19292. case "&&":
  19293. var ll = self.left.evaluate(compressor);
  19294. var rr = self.right.evaluate(compressor);
  19295. if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
  19296. compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
  19297. return make_node(AST_False, self);
  19298. }
  19299. if (ll.length > 1 && ll[1]) {
  19300. return rr[0];
  19301. }
  19302. if (rr.length > 1 && rr[1]) {
  19303. return ll[0];
  19304. }
  19305. break;
  19306. case "||":
  19307. var ll = self.left.evaluate(compressor);
  19308. var rr = self.right.evaluate(compressor);
  19309. if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
  19310. compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
  19311. return make_node(AST_True, self);
  19312. }
  19313. if (ll.length > 1 && !ll[1]) {
  19314. return rr[0];
  19315. }
  19316. if (rr.length > 1 && !rr[1]) {
  19317. return ll[0];
  19318. }
  19319. break;
  19320. case "+":
  19321. var ll = self.left.evaluate(compressor);
  19322. var rr = self.right.evaluate(compressor);
  19323. if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
  19324. (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
  19325. compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
  19326. return make_node(AST_True, self);
  19327. }
  19328. break;
  19329. }
  19330. var exp = self.evaluate(compressor);
  19331. if (exp.length > 1) {
  19332. if (best_of(exp[0], self) !== self)
  19333. return exp[0];
  19334. }
  19335. if (compressor.option("comparisons")) {
  19336. if (!(compressor.parent() instanceof AST_Binary)
  19337. || compressor.parent() instanceof AST_Assign) {
  19338. var negated = make_node(AST_UnaryPrefix, self, {
  19339. operator: "!",
  19340. expression: self.negate(compressor)
  19341. });
  19342. self = best_of(self, negated);
  19343. }
  19344. switch (self.operator) {
  19345. case "<": reverse(">"); break;
  19346. case "<=": reverse(">="); break;
  19347. }
  19348. }
  19349. if (self.operator == "+" && self.right instanceof AST_String
  19350. && self.right.getValue() === "" && self.left instanceof AST_Binary
  19351. && self.left.operator == "+" && self.left.is_string(compressor)) {
  19352. return self.left;
  19353. }
  19354. return self;
  19355. });
  19356. OPT(AST_SymbolRef, function(self, compressor){
  19357. if (self.undeclared()) {
  19358. var defines = compressor.option("global_defs");
  19359. if (defines && defines.hasOwnProperty(self.name)) {
  19360. return make_node_from_constant(compressor, defines[self.name], self);
  19361. }
  19362. switch (self.name) {
  19363. case "undefined":
  19364. return make_node(AST_Undefined, self);
  19365. case "NaN":
  19366. return make_node(AST_NaN, self);
  19367. case "Infinity":
  19368. return make_node(AST_Infinity, self);
  19369. }
  19370. }
  19371. return self;
  19372. });
  19373. OPT(AST_Undefined, function(self, compressor){
  19374. if (compressor.option("unsafe")) {
  19375. var scope = compressor.find_parent(AST_Scope);
  19376. var undef = scope.find_variable("undefined");
  19377. if (undef) {
  19378. var ref = make_node(AST_SymbolRef, self, {
  19379. name : "undefined",
  19380. scope : scope,
  19381. thedef : undef
  19382. });
  19383. ref.reference();
  19384. return ref;
  19385. }
  19386. }
  19387. return self;
  19388. });
  19389. var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
  19390. OPT(AST_Assign, function(self, compressor){
  19391. self = self.lift_sequences(compressor);
  19392. if (self.operator == "="
  19393. && self.left instanceof AST_SymbolRef
  19394. && self.right instanceof AST_Binary
  19395. && self.right.left instanceof AST_SymbolRef
  19396. && self.right.left.name == self.left.name
  19397. && member(self.right.operator, ASSIGN_OPS)) {
  19398. self.operator = self.right.operator + "=";
  19399. self.right = self.right.right;
  19400. }
  19401. return self;
  19402. });
  19403. OPT(AST_Conditional, function(self, compressor){
  19404. if (!compressor.option("conditionals")) return self;
  19405. if (self.condition instanceof AST_Seq) {
  19406. var car = self.condition.car;
  19407. self.condition = self.condition.cdr;
  19408. return AST_Seq.cons(car, self);
  19409. }
  19410. var cond = self.condition.evaluate(compressor);
  19411. if (cond.length > 1) {
  19412. if (cond[1]) {
  19413. compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
  19414. return self.consequent;
  19415. } else {
  19416. compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
  19417. return self.alternative;
  19418. }
  19419. }
  19420. var negated = cond[0].negate(compressor);
  19421. if (best_of(cond[0], negated) === negated) {
  19422. self = make_node(AST_Conditional, self, {
  19423. condition: negated,
  19424. consequent: self.alternative,
  19425. alternative: self.consequent
  19426. });
  19427. }
  19428. var consequent = self.consequent;
  19429. var alternative = self.alternative;
  19430. if (consequent instanceof AST_Assign
  19431. && alternative instanceof AST_Assign
  19432. && consequent.operator == alternative.operator
  19433. && consequent.left.equivalent_to(alternative.left)
  19434. ) {
  19435. /*
  19436. * Stuff like this:
  19437. * if (foo) exp = something; else exp = something_else;
  19438. * ==>
  19439. * exp = foo ? something : something_else;
  19440. */
  19441. self = make_node(AST_Assign, self, {
  19442. operator: consequent.operator,
  19443. left: consequent.left,
  19444. right: make_node(AST_Conditional, self, {
  19445. condition: self.condition,
  19446. consequent: consequent.right,
  19447. alternative: alternative.right
  19448. })
  19449. });
  19450. }
  19451. return self;
  19452. });
  19453. OPT(AST_Boolean, function(self, compressor){
  19454. if (compressor.option("booleans")) {
  19455. var p = compressor.parent();
  19456. if (p instanceof AST_Binary && (p.operator == "=="
  19457. || p.operator == "!=")) {
  19458. compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
  19459. operator : p.operator,
  19460. value : self.value,
  19461. file : p.start.file,
  19462. line : p.start.line,
  19463. col : p.start.col,
  19464. });
  19465. return make_node(AST_Number, self, {
  19466. value: +self.value
  19467. });
  19468. }
  19469. return make_node(AST_UnaryPrefix, self, {
  19470. operator: "!",
  19471. expression: make_node(AST_Number, self, {
  19472. value: 1 - self.value
  19473. })
  19474. });
  19475. }
  19476. return self;
  19477. });
  19478. OPT(AST_Sub, function(self, compressor){
  19479. var prop = self.property;
  19480. if (prop instanceof AST_String && compressor.option("properties")) {
  19481. prop = prop.getValue();
  19482. if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) {
  19483. return make_node(AST_Dot, self, {
  19484. expression : self.expression,
  19485. property : prop
  19486. });
  19487. }
  19488. }
  19489. return self;
  19490. });
  19491. function literals_in_boolean_context(self, compressor) {
  19492. if (compressor.option("booleans") && compressor.in_boolean_context()) {
  19493. return make_node(AST_True, self);
  19494. }
  19495. return self;
  19496. };
  19497. OPT(AST_Array, literals_in_boolean_context);
  19498. OPT(AST_Object, literals_in_boolean_context);
  19499. OPT(AST_RegExp, literals_in_boolean_context);
  19500. })();
  19501. /***********************************************************************
  19502. A JavaScript tokenizer / parser / beautifier / compressor.
  19503. https://github.com/mishoo/UglifyJS2
  19504. -------------------------------- (C) ---------------------------------
  19505. Author: Mihai Bazon
  19506. <mihai.bazon@gmail.com>
  19507. http://mihai.bazon.net/blog
  19508. Distributed under the BSD license:
  19509. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  19510. Redistribution and use in source and binary forms, with or without
  19511. modification, are permitted provided that the following conditions
  19512. are met:
  19513. * Redistributions of source code must retain the above
  19514. copyright notice, this list of conditions and the following
  19515. disclaimer.
  19516. * Redistributions in binary form must reproduce the above
  19517. copyright notice, this list of conditions and the following
  19518. disclaimer in the documentation and/or other materials
  19519. provided with the distribution.
  19520. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  19521. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19522. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19523. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  19524. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  19525. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19526. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  19527. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19528. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  19529. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  19530. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  19531. SUCH DAMAGE.
  19532. ***********************************************************************/
  19533. "use strict";
  19534. // a small wrapper around fitzgen's source-map library
  19535. function SourceMap(options) {
  19536. options = defaults(options, {
  19537. file : null,
  19538. root : null,
  19539. orig : null,
  19540. });
  19541. var generator = new MOZ_SourceMap.SourceMapGenerator({
  19542. file : options.file,
  19543. sourceRoot : options.root
  19544. });
  19545. var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
  19546. function add(source, gen_line, gen_col, orig_line, orig_col, name) {
  19547. if (orig_map) {
  19548. var info = orig_map.originalPositionFor({
  19549. line: orig_line,
  19550. column: orig_col
  19551. });
  19552. source = info.source;
  19553. orig_line = info.line;
  19554. orig_col = info.column;
  19555. name = info.name;
  19556. }
  19557. generator.addMapping({
  19558. generated : { line: gen_line, column: gen_col },
  19559. original : { line: orig_line, column: orig_col },
  19560. source : source,
  19561. name : name
  19562. });
  19563. };
  19564. return {
  19565. add : add,
  19566. get : function() { return generator },
  19567. toString : function() { return generator.toString() }
  19568. };
  19569. };
  19570. /***********************************************************************
  19571. A JavaScript tokenizer / parser / beautifier / compressor.
  19572. https://github.com/mishoo/UglifyJS2
  19573. -------------------------------- (C) ---------------------------------
  19574. Author: Mihai Bazon
  19575. <mihai.bazon@gmail.com>
  19576. http://mihai.bazon.net/blog
  19577. Distributed under the BSD license:
  19578. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  19579. Redistribution and use in source and binary forms, with or without
  19580. modification, are permitted provided that the following conditions
  19581. are met:
  19582. * Redistributions of source code must retain the above
  19583. copyright notice, this list of conditions and the following
  19584. disclaimer.
  19585. * Redistributions in binary form must reproduce the above
  19586. copyright notice, this list of conditions and the following
  19587. disclaimer in the documentation and/or other materials
  19588. provided with the distribution.
  19589. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
  19590. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19591. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19592. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  19593. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  19594. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19595. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  19596. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19597. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  19598. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  19599. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  19600. SUCH DAMAGE.
  19601. ***********************************************************************/
  19602. "use strict";
  19603. (function(){
  19604. var MOZ_TO_ME = {
  19605. TryStatement : function(M) {
  19606. return new AST_Try({
  19607. start : my_start_token(M),
  19608. end : my_end_token(M),
  19609. body : from_moz(M.block).body,
  19610. bcatch : from_moz(M.handlers[0]),
  19611. bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
  19612. });
  19613. },
  19614. CatchClause : function(M) {
  19615. return new AST_Catch({
  19616. start : my_start_token(M),
  19617. end : my_end_token(M),
  19618. argname : from_moz(M.param),
  19619. body : from_moz(M.body).body
  19620. });
  19621. },
  19622. ObjectExpression : function(M) {
  19623. return new AST_Object({
  19624. start : my_start_token(M),
  19625. end : my_end_token(M),
  19626. properties : M.properties.map(function(prop){
  19627. var key = prop.key;
  19628. var name = key.type == "Identifier" ? key.name : key.value;
  19629. var args = {
  19630. start : my_start_token(key),
  19631. end : my_end_token(prop.value),
  19632. key : name,
  19633. value : from_moz(prop.value)
  19634. };
  19635. switch (prop.kind) {
  19636. case "init":
  19637. return new AST_ObjectKeyVal(args);
  19638. case "set":
  19639. args.value.name = from_moz(key);
  19640. return new AST_ObjectSetter(args);
  19641. case "get":
  19642. args.value.name = from_moz(key);
  19643. return new AST_ObjectGetter(args);
  19644. }
  19645. })
  19646. });
  19647. },
  19648. SequenceExpression : function(M) {
  19649. return AST_Seq.from_array(M.expressions.map(from_moz));
  19650. },
  19651. MemberExpression : function(M) {
  19652. return new (M.computed ? AST_Sub : AST_Dot)({
  19653. start : my_start_token(M),
  19654. end : my_end_token(M),
  19655. property : M.computed ? from_moz(M.property) : M.property.name,
  19656. expression : from_moz(M.object)
  19657. });
  19658. },
  19659. SwitchCase : function(M) {
  19660. return new (M.test ? AST_Case : AST_Default)({
  19661. start : my_start_token(M),
  19662. end : my_end_token(M),
  19663. expression : from_moz(M.test),
  19664. body : M.consequent.map(from_moz)
  19665. });
  19666. },
  19667. Literal : function(M) {
  19668. var val = M.value, args = {
  19669. start : my_start_token(M),
  19670. end : my_end_token(M)
  19671. };
  19672. if (val === null) return new AST_Null(args);
  19673. switch (typeof val) {
  19674. case "string":
  19675. args.value = val;
  19676. return new AST_String(args);
  19677. case "number":
  19678. args.value = val;
  19679. return new AST_Number(args);
  19680. case "boolean":
  19681. return new (val ? AST_True : AST_False)(args);
  19682. default:
  19683. args.value = val;
  19684. return new AST_RegExp(args);
  19685. }
  19686. },
  19687. UnaryExpression: From_Moz_Unary,
  19688. UpdateExpression: From_Moz_Unary,
  19689. Identifier: function(M) {
  19690. var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
  19691. return new (M.name == "this" ? AST_This
  19692. : p.type == "LabeledStatement" ? AST_Label
  19693. : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
  19694. : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
  19695. : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
  19696. : p.type == "CatchClause" ? AST_SymbolCatch
  19697. : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
  19698. : AST_SymbolRef)({
  19699. start : my_start_token(M),
  19700. end : my_end_token(M),
  19701. name : M.name
  19702. });
  19703. }
  19704. };
  19705. function From_Moz_Unary(M) {
  19706. var prefix = "prefix" in M ? M.prefix
  19707. : M.type == "UnaryExpression" ? true : false;
  19708. return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
  19709. start : my_start_token(M),
  19710. end : my_end_token(M),
  19711. operator : M.operator,
  19712. expression : from_moz(M.argument)
  19713. });
  19714. };
  19715. var ME_TO_MOZ = {};
  19716. map("Node", AST_Node);
  19717. map("Program", AST_Toplevel, "body@body");
  19718. map("Function", AST_Function, "id>name, params@argnames, body%body");
  19719. map("EmptyStatement", AST_EmptyStatement);
  19720. map("BlockStatement", AST_BlockStatement, "body@body");
  19721. map("ExpressionStatement", AST_SimpleStatement, "expression>body");
  19722. map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
  19723. map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
  19724. map("BreakStatement", AST_Break, "label>label");
  19725. map("ContinueStatement", AST_Continue, "label>label");
  19726. map("WithStatement", AST_With, "object>expression, body>body");
  19727. map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
  19728. map("ReturnStatement", AST_Return, "argument>value");
  19729. map("ThrowStatement", AST_Throw, "argument>value");
  19730. map("WhileStatement", AST_While, "test>condition, body>body");
  19731. map("DoWhileStatement", AST_Do, "test>condition, body>body");
  19732. map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
  19733. map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
  19734. map("DebuggerStatement", AST_Debugger);
  19735. map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
  19736. map("VariableDeclaration", AST_Var, "declarations@definitions");
  19737. map("VariableDeclarator", AST_VarDef, "id>name, init>value");
  19738. map("ThisExpression", AST_This);
  19739. map("ArrayExpression", AST_Array, "elements@elements");
  19740. map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
  19741. map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
  19742. map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
  19743. map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
  19744. map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
  19745. map("NewExpression", AST_New, "callee>expression, arguments@args");
  19746. map("CallExpression", AST_Call, "callee>expression, arguments@args");
  19747. /* -----[ tools ]----- */
  19748. function my_start_token(moznode) {
  19749. return new AST_Token({
  19750. file : moznode.loc && moznode.loc.source,
  19751. line : moznode.loc && moznode.loc.start.line,
  19752. col : moznode.loc && moznode.loc.start.column,
  19753. pos : moznode.start,
  19754. endpos : moznode.start
  19755. });
  19756. };
  19757. function my_end_token(moznode) {
  19758. return new AST_Token({
  19759. file : moznode.loc && moznode.loc.source,
  19760. line : moznode.loc && moznode.loc.end.line,
  19761. col : moznode.loc && moznode.loc.end.column,
  19762. pos : moznode.end,
  19763. endpos : moznode.end
  19764. });
  19765. };
  19766. function map(moztype, mytype, propmap) {
  19767. var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
  19768. moz_to_me += "return new mytype({\n" +
  19769. "start: my_start_token(M),\n" +
  19770. "end: my_end_token(M)";
  19771. if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
  19772. var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
  19773. if (!m) throw new Error("Can't understand property map: " + prop);
  19774. var moz = "M." + m[1], how = m[2], my = m[3];
  19775. moz_to_me += ",\n" + my + ": ";
  19776. if (how == "@") {
  19777. moz_to_me += moz + ".map(from_moz)";
  19778. } else if (how == ">") {
  19779. moz_to_me += "from_moz(" + moz + ")";
  19780. } else if (how == "=") {
  19781. moz_to_me += moz;
  19782. } else if (how == "%") {
  19783. moz_to_me += "from_moz(" + moz + ").body";
  19784. } else throw new Error("Can't understand operator in propmap: " + prop);
  19785. });
  19786. moz_to_me += "\n})}";
  19787. // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
  19788. // console.log(moz_to_me);
  19789. moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
  19790. mytype, my_start_token, my_end_token, from_moz
  19791. );
  19792. return MOZ_TO_ME[moztype] = moz_to_me;
  19793. };
  19794. var FROM_MOZ_STACK = null;
  19795. function from_moz(node) {
  19796. FROM_MOZ_STACK.push(node);
  19797. var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
  19798. FROM_MOZ_STACK.pop();
  19799. return ret;
  19800. };
  19801. AST_Node.from_mozilla_ast = function(node){
  19802. var save_stack = FROM_MOZ_STACK;
  19803. FROM_MOZ_STACK = [];
  19804. var ast = from_moz(node);
  19805. FROM_MOZ_STACK = save_stack;
  19806. return ast;
  19807. };
  19808. })();
  19809. exports.sys = sys;
  19810. exports.MOZ_SourceMap = MOZ_SourceMap;
  19811. exports.UglifyJS = UglifyJS;
  19812. exports.array_to_hash = array_to_hash;
  19813. exports.slice = slice;
  19814. exports.characters = characters;
  19815. exports.member = member;
  19816. exports.find_if = find_if;
  19817. exports.repeat_string = repeat_string;
  19818. exports.DefaultsError = DefaultsError;
  19819. exports.defaults = defaults;
  19820. exports.merge = merge;
  19821. exports.noop = noop;
  19822. exports.MAP = MAP;
  19823. exports.push_uniq = push_uniq;
  19824. exports.string_template = string_template;
  19825. exports.remove = remove;
  19826. exports.mergeSort = mergeSort;
  19827. exports.set_difference = set_difference;
  19828. exports.set_intersection = set_intersection;
  19829. exports.makePredicate = makePredicate;
  19830. exports.all = all;
  19831. exports.Dictionary = Dictionary;
  19832. exports.DEFNODE = DEFNODE;
  19833. exports.AST_Token = AST_Token;
  19834. exports.AST_Node = AST_Node;
  19835. exports.AST_Statement = AST_Statement;
  19836. exports.AST_Debugger = AST_Debugger;
  19837. exports.AST_Directive = AST_Directive;
  19838. exports.AST_SimpleStatement = AST_SimpleStatement;
  19839. exports.walk_body = walk_body;
  19840. exports.AST_Block = AST_Block;
  19841. exports.AST_BlockStatement = AST_BlockStatement;
  19842. exports.AST_EmptyStatement = AST_EmptyStatement;
  19843. exports.AST_StatementWithBody = AST_StatementWithBody;
  19844. exports.AST_LabeledStatement = AST_LabeledStatement;
  19845. exports.AST_DWLoop = AST_DWLoop;
  19846. exports.AST_Do = AST_Do;
  19847. exports.AST_While = AST_While;
  19848. exports.AST_For = AST_For;
  19849. exports.AST_ForIn = AST_ForIn;
  19850. exports.AST_With = AST_With;
  19851. exports.AST_Scope = AST_Scope;
  19852. exports.AST_Toplevel = AST_Toplevel;
  19853. exports.AST_Lambda = AST_Lambda;
  19854. exports.AST_Accessor = AST_Accessor;
  19855. exports.AST_Function = AST_Function;
  19856. exports.AST_Defun = AST_Defun;
  19857. exports.AST_Jump = AST_Jump;
  19858. exports.AST_Exit = AST_Exit;
  19859. exports.AST_Return = AST_Return;
  19860. exports.AST_Throw = AST_Throw;
  19861. exports.AST_LoopControl = AST_LoopControl;
  19862. exports.AST_Break = AST_Break;
  19863. exports.AST_Continue = AST_Continue;
  19864. exports.AST_If = AST_If;
  19865. exports.AST_Switch = AST_Switch;
  19866. exports.AST_SwitchBranch = AST_SwitchBranch;
  19867. exports.AST_Default = AST_Default;
  19868. exports.AST_Case = AST_Case;
  19869. exports.AST_Try = AST_Try;
  19870. exports.AST_Catch = AST_Catch;
  19871. exports.AST_Finally = AST_Finally;
  19872. exports.AST_Definitions = AST_Definitions;
  19873. exports.AST_Var = AST_Var;
  19874. exports.AST_Const = AST_Const;
  19875. exports.AST_VarDef = AST_VarDef;
  19876. exports.AST_Call = AST_Call;
  19877. exports.AST_New = AST_New;
  19878. exports.AST_Seq = AST_Seq;
  19879. exports.AST_PropAccess = AST_PropAccess;
  19880. exports.AST_Dot = AST_Dot;
  19881. exports.AST_Sub = AST_Sub;
  19882. exports.AST_Unary = AST_Unary;
  19883. exports.AST_UnaryPrefix = AST_UnaryPrefix;
  19884. exports.AST_UnaryPostfix = AST_UnaryPostfix;
  19885. exports.AST_Binary = AST_Binary;
  19886. exports.AST_Conditional = AST_Conditional;
  19887. exports.AST_Assign = AST_Assign;
  19888. exports.AST_Array = AST_Array;
  19889. exports.AST_Object = AST_Object;
  19890. exports.AST_ObjectProperty = AST_ObjectProperty;
  19891. exports.AST_ObjectKeyVal = AST_ObjectKeyVal;
  19892. exports.AST_ObjectSetter = AST_ObjectSetter;
  19893. exports.AST_ObjectGetter = AST_ObjectGetter;
  19894. exports.AST_Symbol = AST_Symbol;
  19895. exports.AST_SymbolAccessor = AST_SymbolAccessor;
  19896. exports.AST_SymbolDeclaration = AST_SymbolDeclaration;
  19897. exports.AST_SymbolVar = AST_SymbolVar;
  19898. exports.AST_SymbolConst = AST_SymbolConst;
  19899. exports.AST_SymbolFunarg = AST_SymbolFunarg;
  19900. exports.AST_SymbolDefun = AST_SymbolDefun;
  19901. exports.AST_SymbolLambda = AST_SymbolLambda;
  19902. exports.AST_SymbolCatch = AST_SymbolCatch;
  19903. exports.AST_Label = AST_Label;
  19904. exports.AST_SymbolRef = AST_SymbolRef;
  19905. exports.AST_LabelRef = AST_LabelRef;
  19906. exports.AST_This = AST_This;
  19907. exports.AST_Constant = AST_Constant;
  19908. exports.AST_String = AST_String;
  19909. exports.AST_Number = AST_Number;
  19910. exports.AST_RegExp = AST_RegExp;
  19911. exports.AST_Atom = AST_Atom;
  19912. exports.AST_Null = AST_Null;
  19913. exports.AST_NaN = AST_NaN;
  19914. exports.AST_Undefined = AST_Undefined;
  19915. exports.AST_Hole = AST_Hole;
  19916. exports.AST_Infinity = AST_Infinity;
  19917. exports.AST_Boolean = AST_Boolean;
  19918. exports.AST_False = AST_False;
  19919. exports.AST_True = AST_True;
  19920. exports.TreeWalker = TreeWalker;
  19921. exports.KEYWORDS = KEYWORDS;
  19922. exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
  19923. exports.RESERVED_WORDS = RESERVED_WORDS;
  19924. exports.KEYWORDS_BEFORE_EXPRESSION = KEYWORDS_BEFORE_EXPRESSION;
  19925. exports.OPERATOR_CHARS = OPERATOR_CHARS;
  19926. exports.RE_HEX_NUMBER = RE_HEX_NUMBER;
  19927. exports.RE_OCT_NUMBER = RE_OCT_NUMBER;
  19928. exports.RE_DEC_NUMBER = RE_DEC_NUMBER;
  19929. exports.OPERATORS = OPERATORS;
  19930. exports.WHITESPACE_CHARS = WHITESPACE_CHARS;
  19931. exports.PUNC_BEFORE_EXPRESSION = PUNC_BEFORE_EXPRESSION;
  19932. exports.PUNC_CHARS = PUNC_CHARS;
  19933. exports.REGEXP_MODIFIERS = REGEXP_MODIFIERS;
  19934. exports.UNICODE = UNICODE;
  19935. exports.is_letter = is_letter;
  19936. exports.is_digit = is_digit;
  19937. exports.is_alphanumeric_char = is_alphanumeric_char;
  19938. exports.is_unicode_combining_mark = is_unicode_combining_mark;
  19939. exports.is_unicode_connector_punctuation = is_unicode_connector_punctuation;
  19940. exports.is_identifier = is_identifier;
  19941. exports.is_identifier_start = is_identifier_start;
  19942. exports.is_identifier_char = is_identifier_char;
  19943. exports.is_identifier_string = is_identifier_string;
  19944. exports.parse_js_number = parse_js_number;
  19945. exports.JS_Parse_Error = JS_Parse_Error;
  19946. exports.js_error = js_error;
  19947. exports.is_token = is_token;
  19948. exports.EX_EOF = EX_EOF;
  19949. exports.tokenizer = tokenizer;
  19950. exports.UNARY_PREFIX = UNARY_PREFIX;
  19951. exports.UNARY_POSTFIX = UNARY_POSTFIX;
  19952. exports.ASSIGNMENT = ASSIGNMENT;
  19953. exports.PRECEDENCE = PRECEDENCE;
  19954. exports.STATEMENTS_WITH_LABELS = STATEMENTS_WITH_LABELS;
  19955. exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
  19956. exports.parse = parse;
  19957. exports.TreeTransformer = TreeTransformer;
  19958. exports.SymbolDef = SymbolDef;
  19959. exports.base54 = base54;
  19960. exports.OutputStream = OutputStream;
  19961. exports.Compressor = Compressor;
  19962. exports.SourceMap = SourceMap;
  19963. exports.AST_Node.warn_function = function (txt) { if (typeof console != "undefined" && typeof console.warn === "function") console.warn(txt) }
  19964. exports.minify = function (files, options) {
  19965. options = UglifyJS.defaults(options, {
  19966. outSourceMap : null,
  19967. sourceRoot : null,
  19968. inSourceMap : null,
  19969. fromString : false,
  19970. warnings : false,
  19971. mangle : {},
  19972. output : null,
  19973. compress : {}
  19974. });
  19975. if (typeof files == "string")
  19976. files = [ files ];
  19977. UglifyJS.base54.reset();
  19978. // 1. parse
  19979. var toplevel = null;
  19980. files.forEach(function(file){
  19981. var code = options.fromString
  19982. ? file
  19983. : fs.readFileSync(file, "utf8");
  19984. toplevel = UglifyJS.parse(code, {
  19985. filename: options.fromString ? "?" : file,
  19986. toplevel: toplevel
  19987. });
  19988. });
  19989. // 2. compress
  19990. if (options.compress) {
  19991. var compress = { warnings: options.warnings };
  19992. UglifyJS.merge(compress, options.compress);
  19993. toplevel.figure_out_scope();
  19994. var sq = UglifyJS.Compressor(compress);
  19995. toplevel = toplevel.transform(sq);
  19996. }
  19997. // 3. mangle
  19998. if (options.mangle) {
  19999. toplevel.figure_out_scope();
  20000. toplevel.compute_char_frequency();
  20001. toplevel.mangle_names(options.mangle);
  20002. }
  20003. // 4. output
  20004. var inMap = options.inSourceMap;
  20005. var output = {};
  20006. if (typeof options.inSourceMap == "string") {
  20007. inMap = fs.readFileSync(options.inSourceMap, "utf8");
  20008. }
  20009. if (options.outSourceMap) {
  20010. output.source_map = UglifyJS.SourceMap({
  20011. file: options.outSourceMap,
  20012. orig: inMap,
  20013. root: options.sourceRoot
  20014. });
  20015. }
  20016. if (options.output) {
  20017. UglifyJS.merge(output, options.output);
  20018. }
  20019. var stream = UglifyJS.OutputStream(output);
  20020. toplevel.print(stream);
  20021. return {
  20022. code : stream + "",
  20023. map : output.source_map + ""
  20024. };
  20025. };
  20026. exports.describe_ast = function () {
  20027. var out = UglifyJS.OutputStream({ beautify: true });
  20028. function doitem(ctor) {
  20029. out.print("AST_" + ctor.TYPE);
  20030. var props = ctor.SELF_PROPS.filter(function(prop){
  20031. return !/^\$/.test(prop);
  20032. });
  20033. if (props.length > 0) {
  20034. out.space();
  20035. out.with_parens(function(){
  20036. props.forEach(function(prop, i){
  20037. if (i) out.space();
  20038. out.print(prop);
  20039. });
  20040. });
  20041. }
  20042. if (ctor.documentation) {
  20043. out.space();
  20044. out.print_string(ctor.documentation);
  20045. }
  20046. if (ctor.SUBCLASSES.length > 0) {
  20047. out.space();
  20048. out.with_block(function(){
  20049. ctor.SUBCLASSES.forEach(function(ctor, i){
  20050. out.indent();
  20051. doitem(ctor);
  20052. out.newline();
  20053. });
  20054. });
  20055. }
  20056. };
  20057. doitem(UglifyJS.AST_Node);
  20058. return out + "";
  20059. };
  20060. },{"source-map":47,"util":32}],58:[function(require,module,exports){
  20061. // jshint -W001
  20062. "use strict";
  20063. // Identifiers provided by the ECMAScript standard.
  20064. exports.reservedVars = {
  20065. arguments : false,
  20066. NaN : false
  20067. };
  20068. exports.ecmaIdentifiers = {
  20069. Array : false,
  20070. Boolean : false,
  20071. Date : false,
  20072. decodeURI : false,
  20073. decodeURIComponent : false,
  20074. encodeURI : false,
  20075. encodeURIComponent : false,
  20076. Error : false,
  20077. "eval" : false,
  20078. EvalError : false,
  20079. Function : false,
  20080. hasOwnProperty : false,
  20081. isFinite : false,
  20082. isNaN : false,
  20083. JSON : false,
  20084. Math : false,
  20085. Map : false,
  20086. Number : false,
  20087. Object : false,
  20088. parseInt : false,
  20089. parseFloat : false,
  20090. RangeError : false,
  20091. ReferenceError : false,
  20092. RegExp : false,
  20093. Set : false,
  20094. String : false,
  20095. SyntaxError : false,
  20096. TypeError : false,
  20097. URIError : false,
  20098. WeakMap : false
  20099. };
  20100. // Global variables commonly provided by a web browser environment.
  20101. exports.browser = {
  20102. Audio : false,
  20103. Blob : false,
  20104. addEventListener : false,
  20105. applicationCache : false,
  20106. atob : false,
  20107. blur : false,
  20108. btoa : false,
  20109. clearInterval : false,
  20110. clearTimeout : false,
  20111. close : false,
  20112. closed : false,
  20113. CustomEvent : false,
  20114. DOMParser : false,
  20115. defaultStatus : false,
  20116. document : false,
  20117. Element : false,
  20118. ElementTimeControl : false,
  20119. event : false,
  20120. FileReader : false,
  20121. FormData : false,
  20122. focus : false,
  20123. frames : false,
  20124. getComputedStyle : false,
  20125. HTMLElement : false,
  20126. HTMLAnchorElement : false,
  20127. HTMLBaseElement : false,
  20128. HTMLBlockquoteElement: false,
  20129. HTMLBodyElement : false,
  20130. HTMLBRElement : false,
  20131. HTMLButtonElement : false,
  20132. HTMLCanvasElement : false,
  20133. HTMLDirectoryElement : false,
  20134. HTMLDivElement : false,
  20135. HTMLDListElement : false,
  20136. HTMLFieldSetElement : false,
  20137. HTMLFontElement : false,
  20138. HTMLFormElement : false,
  20139. HTMLFrameElement : false,
  20140. HTMLFrameSetElement : false,
  20141. HTMLHeadElement : false,
  20142. HTMLHeadingElement : false,
  20143. HTMLHRElement : false,
  20144. HTMLHtmlElement : false,
  20145. HTMLIFrameElement : false,
  20146. HTMLImageElement : false,
  20147. HTMLInputElement : false,
  20148. HTMLIsIndexElement : false,
  20149. HTMLLabelElement : false,
  20150. HTMLLayerElement : false,
  20151. HTMLLegendElement : false,
  20152. HTMLLIElement : false,
  20153. HTMLLinkElement : false,
  20154. HTMLMapElement : false,
  20155. HTMLMenuElement : false,
  20156. HTMLMetaElement : false,
  20157. HTMLModElement : false,
  20158. HTMLObjectElement : false,
  20159. HTMLOListElement : false,
  20160. HTMLOptGroupElement : false,
  20161. HTMLOptionElement : false,
  20162. HTMLParagraphElement : false,
  20163. HTMLParamElement : false,
  20164. HTMLPreElement : false,
  20165. HTMLQuoteElement : false,
  20166. HTMLScriptElement : false,
  20167. HTMLSelectElement : false,
  20168. HTMLStyleElement : false,
  20169. HTMLTableCaptionElement: false,
  20170. HTMLTableCellElement : false,
  20171. HTMLTableColElement : false,
  20172. HTMLTableElement : false,
  20173. HTMLTableRowElement : false,
  20174. HTMLTableSectionElement: false,
  20175. HTMLTextAreaElement : false,
  20176. HTMLTitleElement : false,
  20177. HTMLUListElement : false,
  20178. HTMLVideoElement : false,
  20179. history : false,
  20180. Image : false,
  20181. length : false,
  20182. localStorage : false,
  20183. location : false,
  20184. MessageChannel : false,
  20185. MessageEvent : false,
  20186. MessagePort : false,
  20187. MouseEvent : false,
  20188. moveBy : false,
  20189. moveTo : false,
  20190. MutationObserver : false,
  20191. name : false,
  20192. Node : false,
  20193. NodeFilter : false,
  20194. navigator : false,
  20195. onbeforeunload : true,
  20196. onblur : true,
  20197. onerror : true,
  20198. onfocus : true,
  20199. onload : true,
  20200. onresize : true,
  20201. onunload : true,
  20202. open : false,
  20203. openDatabase : false,
  20204. opener : false,
  20205. Option : false,
  20206. parent : false,
  20207. print : false,
  20208. removeEventListener : false,
  20209. resizeBy : false,
  20210. resizeTo : false,
  20211. screen : false,
  20212. scroll : false,
  20213. scrollBy : false,
  20214. scrollTo : false,
  20215. sessionStorage : false,
  20216. setInterval : false,
  20217. setTimeout : false,
  20218. SharedWorker : false,
  20219. status : false,
  20220. SVGAElement : false,
  20221. SVGAltGlyphDefElement: false,
  20222. SVGAltGlyphElement : false,
  20223. SVGAltGlyphItemElement: false,
  20224. SVGAngle : false,
  20225. SVGAnimateColorElement: false,
  20226. SVGAnimateElement : false,
  20227. SVGAnimateMotionElement: false,
  20228. SVGAnimateTransformElement: false,
  20229. SVGAnimatedAngle : false,
  20230. SVGAnimatedBoolean : false,
  20231. SVGAnimatedEnumeration: false,
  20232. SVGAnimatedInteger : false,
  20233. SVGAnimatedLength : false,
  20234. SVGAnimatedLengthList: false,
  20235. SVGAnimatedNumber : false,
  20236. SVGAnimatedNumberList: false,
  20237. SVGAnimatedPathData : false,
  20238. SVGAnimatedPoints : false,
  20239. SVGAnimatedPreserveAspectRatio: false,
  20240. SVGAnimatedRect : false,
  20241. SVGAnimatedString : false,
  20242. SVGAnimatedTransformList: false,
  20243. SVGAnimationElement : false,
  20244. SVGCSSRule : false,
  20245. SVGCircleElement : false,
  20246. SVGClipPathElement : false,
  20247. SVGColor : false,
  20248. SVGColorProfileElement: false,
  20249. SVGColorProfileRule : false,
  20250. SVGComponentTransferFunctionElement: false,
  20251. SVGCursorElement : false,
  20252. SVGDefsElement : false,
  20253. SVGDescElement : false,
  20254. SVGDocument : false,
  20255. SVGElement : false,
  20256. SVGElementInstance : false,
  20257. SVGElementInstanceList: false,
  20258. SVGEllipseElement : false,
  20259. SVGExternalResourcesRequired: false,
  20260. SVGFEBlendElement : false,
  20261. SVGFEColorMatrixElement: false,
  20262. SVGFEComponentTransferElement: false,
  20263. SVGFECompositeElement: false,
  20264. SVGFEConvolveMatrixElement: false,
  20265. SVGFEDiffuseLightingElement: false,
  20266. SVGFEDisplacementMapElement: false,
  20267. SVGFEDistantLightElement: false,
  20268. SVGFEFloodElement : false,
  20269. SVGFEFuncAElement : false,
  20270. SVGFEFuncBElement : false,
  20271. SVGFEFuncGElement : false,
  20272. SVGFEFuncRElement : false,
  20273. SVGFEGaussianBlurElement: false,
  20274. SVGFEImageElement : false,
  20275. SVGFEMergeElement : false,
  20276. SVGFEMergeNodeElement: false,
  20277. SVGFEMorphologyElement: false,
  20278. SVGFEOffsetElement : false,
  20279. SVGFEPointLightElement: false,
  20280. SVGFESpecularLightingElement: false,
  20281. SVGFESpotLightElement: false,
  20282. SVGFETileElement : false,
  20283. SVGFETurbulenceElement: false,
  20284. SVGFilterElement : false,
  20285. SVGFilterPrimitiveStandardAttributes: false,
  20286. SVGFitToViewBox : false,
  20287. SVGFontElement : false,
  20288. SVGFontFaceElement : false,
  20289. SVGFontFaceFormatElement: false,
  20290. SVGFontFaceNameElement: false,
  20291. SVGFontFaceSrcElement: false,
  20292. SVGFontFaceUriElement: false,
  20293. SVGForeignObjectElement: false,
  20294. SVGGElement : false,
  20295. SVGGlyphElement : false,
  20296. SVGGlyphRefElement : false,
  20297. SVGGradientElement : false,
  20298. SVGHKernElement : false,
  20299. SVGICCColor : false,
  20300. SVGImageElement : false,
  20301. SVGLangSpace : false,
  20302. SVGLength : false,
  20303. SVGLengthList : false,
  20304. SVGLineElement : false,
  20305. SVGLinearGradientElement: false,
  20306. SVGLocatable : false,
  20307. SVGMPathElement : false,
  20308. SVGMarkerElement : false,
  20309. SVGMaskElement : false,
  20310. SVGMatrix : false,
  20311. SVGMetadataElement : false,
  20312. SVGMissingGlyphElement: false,
  20313. SVGNumber : false,
  20314. SVGNumberList : false,
  20315. SVGPaint : false,
  20316. SVGPathElement : false,
  20317. SVGPathSeg : false,
  20318. SVGPathSegArcAbs : false,
  20319. SVGPathSegArcRel : false,
  20320. SVGPathSegClosePath : false,
  20321. SVGPathSegCurvetoCubicAbs: false,
  20322. SVGPathSegCurvetoCubicRel: false,
  20323. SVGPathSegCurvetoCubicSmoothAbs: false,
  20324. SVGPathSegCurvetoCubicSmoothRel: false,
  20325. SVGPathSegCurvetoQuadraticAbs: false,
  20326. SVGPathSegCurvetoQuadraticRel: false,
  20327. SVGPathSegCurvetoQuadraticSmoothAbs: false,
  20328. SVGPathSegCurvetoQuadraticSmoothRel: false,
  20329. SVGPathSegLinetoAbs : false,
  20330. SVGPathSegLinetoHorizontalAbs: false,
  20331. SVGPathSegLinetoHorizontalRel: false,
  20332. SVGPathSegLinetoRel : false,
  20333. SVGPathSegLinetoVerticalAbs: false,
  20334. SVGPathSegLinetoVerticalRel: false,
  20335. SVGPathSegList : false,
  20336. SVGPathSegMovetoAbs : false,
  20337. SVGPathSegMovetoRel : false,
  20338. SVGPatternElement : false,
  20339. SVGPoint : false,
  20340. SVGPointList : false,
  20341. SVGPolygonElement : false,
  20342. SVGPolylineElement : false,
  20343. SVGPreserveAspectRatio: false,
  20344. SVGRadialGradientElement: false,
  20345. SVGRect : false,
  20346. SVGRectElement : false,
  20347. SVGRenderingIntent : false,
  20348. SVGSVGElement : false,
  20349. SVGScriptElement : false,
  20350. SVGSetElement : false,
  20351. SVGStopElement : false,
  20352. SVGStringList : false,
  20353. SVGStylable : false,
  20354. SVGStyleElement : false,
  20355. SVGSwitchElement : false,
  20356. SVGSymbolElement : false,
  20357. SVGTRefElement : false,
  20358. SVGTSpanElement : false,
  20359. SVGTests : false,
  20360. SVGTextContentElement: false,
  20361. SVGTextElement : false,
  20362. SVGTextPathElement : false,
  20363. SVGTextPositioningElement: false,
  20364. SVGTitleElement : false,
  20365. SVGTransform : false,
  20366. SVGTransformList : false,
  20367. SVGTransformable : false,
  20368. SVGURIReference : false,
  20369. SVGUnitTypes : false,
  20370. SVGUseElement : false,
  20371. SVGVKernElement : false,
  20372. SVGViewElement : false,
  20373. SVGViewSpec : false,
  20374. SVGZoomAndPan : false,
  20375. TimeEvent : false,
  20376. top : false,
  20377. WebSocket : false,
  20378. window : false,
  20379. Worker : false,
  20380. XMLHttpRequest : false,
  20381. XMLSerializer : false,
  20382. XPathEvaluator : false,
  20383. XPathException : false,
  20384. XPathExpression : false,
  20385. XPathNamespace : false,
  20386. XPathNSResolver : false,
  20387. XPathResult : false
  20388. };
  20389. exports.devel = {
  20390. alert : false,
  20391. confirm: false,
  20392. console: false,
  20393. Debug : false,
  20394. opera : false,
  20395. prompt : false
  20396. };
  20397. exports.worker = {
  20398. importScripts: true,
  20399. postMessage : true,
  20400. self : true
  20401. };
  20402. // Widely adopted global names that are not part of ECMAScript standard
  20403. exports.nonstandard = {
  20404. escape : false,
  20405. unescape: false
  20406. };
  20407. // Globals provided by popular JavaScript environments.
  20408. exports.couch = {
  20409. "require" : false,
  20410. respond : false,
  20411. getRow : false,
  20412. emit : false,
  20413. send : false,
  20414. start : false,
  20415. sum : false,
  20416. log : false,
  20417. exports : false,
  20418. module : false,
  20419. provides : false
  20420. };
  20421. exports.node = {
  20422. __filename : false,
  20423. __dirname : false,
  20424. Buffer : false,
  20425. console : false,
  20426. exports : true, // In Node it is ok to exports = module.exports = foo();
  20427. GLOBAL : false,
  20428. global : false,
  20429. module : false,
  20430. process : false,
  20431. require : false,
  20432. setTimeout : false,
  20433. clearTimeout : false,
  20434. setInterval : false,
  20435. clearInterval : false,
  20436. setImmediate : false, // v0.9.1+
  20437. clearImmediate: false // v0.9.1+
  20438. };
  20439. exports.phantom = {
  20440. phantom : true,
  20441. require : true,
  20442. WebPage : true,
  20443. console : true, // in examples, but undocumented
  20444. exports : true // v1.7+
  20445. };
  20446. exports.rhino = {
  20447. defineClass : false,
  20448. deserialize : false,
  20449. gc : false,
  20450. help : false,
  20451. importPackage: false,
  20452. "java" : false,
  20453. load : false,
  20454. loadClass : false,
  20455. print : false,
  20456. quit : false,
  20457. readFile : false,
  20458. readUrl : false,
  20459. runCommand : false,
  20460. seal : false,
  20461. serialize : false,
  20462. spawn : false,
  20463. sync : false,
  20464. toint32 : false,
  20465. version : false
  20466. };
  20467. exports.shelljs = {
  20468. target : false,
  20469. echo : false,
  20470. exit : false,
  20471. cd : false,
  20472. pwd : false,
  20473. ls : false,
  20474. find : false,
  20475. cp : false,
  20476. rm : false,
  20477. mv : false,
  20478. mkdir : false,
  20479. test : false,
  20480. cat : false,
  20481. sed : false,
  20482. grep : false,
  20483. which : false,
  20484. dirs : false,
  20485. pushd : false,
  20486. popd : false,
  20487. env : false,
  20488. exec : false,
  20489. chmod : false,
  20490. config : false,
  20491. error : false,
  20492. tempdir : false
  20493. };
  20494. exports.typed = {
  20495. ArrayBuffer : false,
  20496. ArrayBufferView : false,
  20497. DataView : false,
  20498. Float32Array : false,
  20499. Float64Array : false,
  20500. Int16Array : false,
  20501. Int32Array : false,
  20502. Int8Array : false,
  20503. Uint16Array : false,
  20504. Uint32Array : false,
  20505. Uint8Array : false,
  20506. Uint8ClampedArray : false
  20507. };
  20508. exports.wsh = {
  20509. ActiveXObject : true,
  20510. Enumerator : true,
  20511. GetObject : true,
  20512. ScriptEngine : true,
  20513. ScriptEngineBuildVersion : true,
  20514. ScriptEngineMajorVersion : true,
  20515. ScriptEngineMinorVersion : true,
  20516. VBArray : true,
  20517. WSH : true,
  20518. WScript : true,
  20519. XDomainRequest : true
  20520. };
  20521. // Globals provided by popular JavaScript libraries.
  20522. exports.dojo = {
  20523. dojo : false,
  20524. dijit : false,
  20525. dojox : false,
  20526. define : false,
  20527. "require": false
  20528. };
  20529. exports.jquery = {
  20530. "$" : false,
  20531. jQuery : false
  20532. };
  20533. exports.mootools = {
  20534. "$" : false,
  20535. "$$" : false,
  20536. Asset : false,
  20537. Browser : false,
  20538. Chain : false,
  20539. Class : false,
  20540. Color : false,
  20541. Cookie : false,
  20542. Core : false,
  20543. Document : false,
  20544. DomReady : false,
  20545. DOMEvent : false,
  20546. DOMReady : false,
  20547. Drag : false,
  20548. Element : false,
  20549. Elements : false,
  20550. Event : false,
  20551. Events : false,
  20552. Fx : false,
  20553. Group : false,
  20554. Hash : false,
  20555. HtmlTable : false,
  20556. Iframe : false,
  20557. IframeShim : false,
  20558. InputValidator: false,
  20559. instanceOf : false,
  20560. Keyboard : false,
  20561. Locale : false,
  20562. Mask : false,
  20563. MooTools : false,
  20564. Native : false,
  20565. Options : false,
  20566. OverText : false,
  20567. Request : false,
  20568. Scroller : false,
  20569. Slick : false,
  20570. Slider : false,
  20571. Sortables : false,
  20572. Spinner : false,
  20573. Swiff : false,
  20574. Tips : false,
  20575. Type : false,
  20576. typeOf : false,
  20577. URI : false,
  20578. Window : false
  20579. };
  20580. exports.prototypejs = {
  20581. "$" : false,
  20582. "$$" : false,
  20583. "$A" : false,
  20584. "$F" : false,
  20585. "$H" : false,
  20586. "$R" : false,
  20587. "$break" : false,
  20588. "$continue" : false,
  20589. "$w" : false,
  20590. Abstract : false,
  20591. Ajax : false,
  20592. Class : false,
  20593. Enumerable : false,
  20594. Element : false,
  20595. Event : false,
  20596. Field : false,
  20597. Form : false,
  20598. Hash : false,
  20599. Insertion : false,
  20600. ObjectRange : false,
  20601. PeriodicalExecuter: false,
  20602. Position : false,
  20603. Prototype : false,
  20604. Selector : false,
  20605. Template : false,
  20606. Toggle : false,
  20607. Try : false,
  20608. Autocompleter : false,
  20609. Builder : false,
  20610. Control : false,
  20611. Draggable : false,
  20612. Draggables : false,
  20613. Droppables : false,
  20614. Effect : false,
  20615. Sortable : false,
  20616. SortableObserver : false,
  20617. Sound : false,
  20618. Scriptaculous : false
  20619. };
  20620. exports.yui = {
  20621. YUI : false,
  20622. Y : false,
  20623. YUI_config: false
  20624. };
  20625. },{}]},{},[5])
  20626. (5)
  20627. });