index.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /***********************************************************************
  2. A JavaScript tokenizer / parser / beautifier / compressor.
  3. https://github.com/mishoo/UglifyJS2
  4. -------------------------------- (C) ---------------------------------
  5. Author: Mihai Bazon
  6. <mihai.bazon@gmail.com>
  7. http://mihai.bazon.net/blog
  8. Distributed under the BSD license:
  9. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. * Redistributions of source code must retain the above
  14. copyright notice, this list of conditions and the following
  15. disclaimer.
  16. * Redistributions in binary form must reproduce the above
  17. copyright notice, this list of conditions and the following
  18. disclaimer in the documentation and/or other materials
  19. provided with the distribution.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
  21. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  24. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  25. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  29. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. SUCH DAMAGE.
  32. ***********************************************************************/
  33. "use strict";
  34. import { AST_Node } from "../ast.js";
  35. function characters(str) {
  36. return str.split("");
  37. }
  38. function member(name, array) {
  39. return array.includes(name);
  40. }
  41. class DefaultsError extends Error {
  42. constructor(msg, defs) {
  43. super();
  44. this.name = "DefaultsError";
  45. this.message = msg;
  46. this.defs = defs;
  47. }
  48. }
  49. function defaults(args, defs, croak) {
  50. if (args === true) {
  51. args = {};
  52. } else if (args != null && typeof args === "object") {
  53. args = {...args};
  54. }
  55. const ret = args || {};
  56. if (croak) for (const i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
  57. throw new DefaultsError("`" + i + "` is not a supported option", defs);
  58. }
  59. for (const i in defs) if (HOP(defs, i)) {
  60. if (!args || !HOP(args, i)) {
  61. ret[i] = defs[i];
  62. } else if (i === "ecma") {
  63. let ecma = args[i] | 0;
  64. if (ecma > 5 && ecma < 2015) ecma += 2009;
  65. ret[i] = ecma;
  66. } else {
  67. ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
  68. }
  69. }
  70. return ret;
  71. }
  72. function noop() {}
  73. function return_false() { return false; }
  74. function return_true() { return true; }
  75. function return_this() { return this; }
  76. function return_null() { return null; }
  77. var MAP = (function() {
  78. function MAP(a, tw, allow_splicing = true) {
  79. const new_a = [];
  80. for (let i = 0; i < a.length; ++i) {
  81. let item = a[i];
  82. let ret = item.transform(tw, allow_splicing);
  83. if (ret instanceof AST_Node) {
  84. new_a.push(ret);
  85. } else if (ret instanceof Splice) {
  86. new_a.push(...ret.v);
  87. }
  88. }
  89. return new_a;
  90. }
  91. MAP.splice = function(val) { return new Splice(val); };
  92. MAP.skip = {};
  93. function Splice(val) { this.v = val; }
  94. return MAP;
  95. })();
  96. function make_node(ctor, orig, props) {
  97. if (!props) props = {};
  98. if (orig) {
  99. if (!props.start) props.start = orig.start;
  100. if (!props.end) props.end = orig.end;
  101. }
  102. return new ctor(props);
  103. }
  104. function push_uniq(array, el) {
  105. if (!array.includes(el))
  106. array.push(el);
  107. }
  108. function string_template(text, props) {
  109. return text.replace(/{(.+?)}/g, function(str, p) {
  110. return props && props[p];
  111. });
  112. }
  113. function remove(array, el) {
  114. for (var i = array.length; --i >= 0;) {
  115. if (array[i] === el) array.splice(i, 1);
  116. }
  117. }
  118. function mergeSort(array, cmp) {
  119. if (array.length < 2) return array.slice();
  120. function merge(a, b) {
  121. var r = [], ai = 0, bi = 0, i = 0;
  122. while (ai < a.length && bi < b.length) {
  123. cmp(a[ai], b[bi]) <= 0
  124. ? r[i++] = a[ai++]
  125. : r[i++] = b[bi++];
  126. }
  127. if (ai < a.length) r.push.apply(r, a.slice(ai));
  128. if (bi < b.length) r.push.apply(r, b.slice(bi));
  129. return r;
  130. }
  131. function _ms(a) {
  132. if (a.length <= 1)
  133. return a;
  134. var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
  135. left = _ms(left);
  136. right = _ms(right);
  137. return merge(left, right);
  138. }
  139. return _ms(array);
  140. }
  141. function makePredicate(words) {
  142. if (!Array.isArray(words)) words = words.split(" ");
  143. return new Set(words.sort());
  144. }
  145. function map_add(map, key, value) {
  146. if (map.has(key)) {
  147. map.get(key).push(value);
  148. } else {
  149. map.set(key, [ value ]);
  150. }
  151. }
  152. function map_from_object(obj) {
  153. var map = new Map();
  154. for (var key in obj) {
  155. if (HOP(obj, key) && key.charAt(0) === "$") {
  156. map.set(key.substr(1), obj[key]);
  157. }
  158. }
  159. return map;
  160. }
  161. function map_to_object(map) {
  162. var obj = Object.create(null);
  163. map.forEach(function (value, key) {
  164. obj["$" + key] = value;
  165. });
  166. return obj;
  167. }
  168. function HOP(obj, prop) {
  169. return Object.prototype.hasOwnProperty.call(obj, prop);
  170. }
  171. function keep_name(keep_setting, name) {
  172. return keep_setting === true
  173. || (keep_setting instanceof RegExp && keep_setting.test(name));
  174. }
  175. var lineTerminatorEscape = {
  176. "\0": "0",
  177. "\n": "n",
  178. "\r": "r",
  179. "\u2028": "u2028",
  180. "\u2029": "u2029",
  181. };
  182. function regexp_source_fix(source) {
  183. // V8 does not escape line terminators in regexp patterns in node 12
  184. // We'll also remove literal \0
  185. return source.replace(/[\0\n\r\u2028\u2029]/g, function (match, offset) {
  186. var escaped = source[offset - 1] == "\\"
  187. && (source[offset - 2] != "\\"
  188. || /(?:^|[^\\])(?:\\{2})*$/.test(source.slice(0, offset - 1)));
  189. return (escaped ? "" : "\\") + lineTerminatorEscape[match];
  190. });
  191. }
  192. // Subset of regexps that is not going to cause regexp based DDOS
  193. // https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
  194. const re_safe_regexp = /^[\\/|\0\s\w^$.[\]()]*$/;
  195. /** Check if the regexp is safe for Terser to create without risking a RegExp DOS */
  196. export const regexp_is_safe = (source) => re_safe_regexp.test(source);
  197. const all_flags = "dgimsuyv";
  198. function sort_regexp_flags(flags) {
  199. const existing_flags = new Set(flags.split(""));
  200. let out = "";
  201. for (const flag of all_flags) {
  202. if (existing_flags.has(flag)) {
  203. out += flag;
  204. existing_flags.delete(flag);
  205. }
  206. }
  207. if (existing_flags.size) {
  208. // Flags Terser doesn't know about
  209. existing_flags.forEach(flag => { out += flag; });
  210. }
  211. return out;
  212. }
  213. function has_annotation(node, annotation) {
  214. return node._annotations & annotation;
  215. }
  216. function set_annotation(node, annotation) {
  217. node._annotations |= annotation;
  218. }
  219. function clear_annotation(node, annotation) {
  220. node._annotations &= ~annotation;
  221. }
  222. export {
  223. characters,
  224. defaults,
  225. HOP,
  226. keep_name,
  227. make_node,
  228. makePredicate,
  229. map_add,
  230. map_from_object,
  231. map_to_object,
  232. MAP,
  233. member,
  234. mergeSort,
  235. noop,
  236. push_uniq,
  237. regexp_source_fix,
  238. remove,
  239. return_false,
  240. return_null,
  241. return_this,
  242. return_true,
  243. sort_regexp_flags,
  244. string_template,
  245. has_annotation,
  246. set_annotation,
  247. clear_annotation,
  248. };