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