Buckets:
arudradey/ml-cpu-storage / emsdk /upstream /emscripten /node_modules /terser /lib /compress /common.js
| /*********************************************************************** | |
| A JavaScript tokenizer / parser / beautifier / compressor. | |
| https://github.com/mishoo/UglifyJS2 | |
| -------------------------------- (C) --------------------------------- | |
| Author: Mihai Bazon | |
| <mihai.bazon@gmail.com> | |
| http://mihai.bazon.net/blog | |
| Distributed under the BSD license: | |
| Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com> | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| * Redistributions of source code must retain the above | |
| copyright notice, this list of conditions and the following | |
| disclaimer. | |
| * Redistributions in binary form must reproduce the above | |
| copyright notice, this list of conditions and the following | |
| disclaimer in the documentation and/or other materials | |
| provided with the distribution. | |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY | |
| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE | |
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
| OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
| TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |
| THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| SUCH DAMAGE. | |
| ***********************************************************************/ | |
| import { | |
| AST_Array, | |
| AST_Arrow, | |
| AST_BigInt, | |
| AST_BlockStatement, | |
| AST_Call, | |
| AST_Chain, | |
| AST_Class, | |
| AST_Const, | |
| AST_Constant, | |
| AST_DefClass, | |
| AST_Defun, | |
| AST_EmptyStatement, | |
| AST_Export, | |
| AST_False, | |
| AST_Function, | |
| AST_Import, | |
| AST_Infinity, | |
| AST_LabeledStatement, | |
| AST_Lambda, | |
| AST_Let, | |
| AST_LoopControl, | |
| AST_NaN, | |
| AST_Node, | |
| AST_Null, | |
| AST_Number, | |
| AST_Object, | |
| AST_ObjectKeyVal, | |
| AST_PropAccess, | |
| AST_RegExp, | |
| AST_Scope, | |
| AST_Sequence, | |
| AST_SimpleStatement, | |
| AST_Statement, | |
| AST_String, | |
| AST_SymbolRef, | |
| AST_True, | |
| AST_UnaryPrefix, | |
| AST_Undefined, | |
| TreeWalker, | |
| walk, | |
| walk_abort, | |
| walk_parent, | |
| } from "../ast.js"; | |
| import { make_node, regexp_source_fix, string_template, makePredicate } from "../utils/index.js"; | |
| import { first_in_statement } from "../utils/first_in_statement.js"; | |
| import { has_flag, TOP } from "./compressor-flags.js"; | |
| export function merge_sequence(array, node) { | |
| if (node instanceof AST_Sequence) { | |
| array.push(...node.expressions); | |
| } else { | |
| array.push(node); | |
| } | |
| return array; | |
| } | |
| export function make_sequence(orig, expressions) { | |
| if (expressions.length == 1) return expressions[0]; | |
| if (expressions.length == 0) throw new Error("trying to create a sequence with length zero!"); | |
| return make_node(AST_Sequence, orig, { | |
| expressions: expressions.reduce(merge_sequence, []) | |
| }); | |
| } | |
| export function make_empty_function(self) { | |
| return make_node(AST_Function, self, { | |
| uses_arguments: false, | |
| argnames: [], | |
| body: [], | |
| is_generator: false, | |
| async: false, | |
| variables: new Map(), | |
| uses_with: false, | |
| uses_eval: false, | |
| parent_scope: null, | |
| enclosed: [], | |
| cname: 0, | |
| block_scope: undefined, | |
| }); | |
| } | |
| export function make_node_from_constant(val, orig) { | |
| switch (typeof val) { | |
| case "string": | |
| return make_node(AST_String, orig, { | |
| value: val | |
| }); | |
| case "number": | |
| if (isNaN(val)) return make_node(AST_NaN, orig); | |
| if (isFinite(val)) { | |
| return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, { | |
| operator: "-", | |
| expression: make_node(AST_Number, orig, { value: -val }) | |
| }) : make_node(AST_Number, orig, { value: val }); | |
| } | |
| return val < 0 ? make_node(AST_UnaryPrefix, orig, { | |
| operator: "-", | |
| expression: make_node(AST_Infinity, orig) | |
| }) : make_node(AST_Infinity, orig); | |
| case "bigint": | |
| return make_node(AST_BigInt, orig, { value: val.toString() }); | |
| case "boolean": | |
| return make_node(val ? AST_True : AST_False, orig); | |
| case "undefined": | |
| return make_node(AST_Undefined, orig); | |
| default: | |
| if (val === null) { | |
| return make_node(AST_Null, orig, { value: null }); | |
| } | |
| if (val instanceof RegExp) { | |
| return make_node(AST_RegExp, orig, { | |
| value: { | |
| source: regexp_source_fix(val.source), | |
| flags: val.flags | |
| } | |
| }); | |
| } | |
| throw new Error(string_template("Can't handle constant of type: {type}", { | |
| type: typeof val | |
| })); | |
| } | |
| } | |
| export function best_of_expression(ast1, ast2) { | |
| return ast1.size() > ast2.size() ? ast2 : ast1; | |
| } | |
| export function best_of_statement(ast1, ast2) { | |
| return best_of_expression( | |
| make_node(AST_SimpleStatement, ast1, { | |
| body: ast1 | |
| }), | |
| make_node(AST_SimpleStatement, ast2, { | |
| body: ast2 | |
| }) | |
| ).body; | |
| } | |
| /** Find which node is smaller, and return that */ | |
| export function best_of(compressor, ast1, ast2) { | |
| if (first_in_statement(compressor)) { | |
| return best_of_statement(ast1, ast2); | |
| } else { | |
| return best_of_expression(ast1, ast2); | |
| } | |
| } | |
| /** Simplify an object property's key, if possible */ | |
| export function get_simple_key(key) { | |
| if (key instanceof AST_Constant) { | |
| return key.getValue(); | |
| } | |
| if (key instanceof AST_UnaryPrefix | |
| && key.operator == "void" | |
| && key.expression instanceof AST_Constant) { | |
| return; | |
| } | |
| return key; | |
| } | |
| export function read_property(obj, key) { | |
| key = get_simple_key(key); | |
| if (key instanceof AST_Node) return; | |
| var value; | |
| if (obj instanceof AST_Array) { | |
| var elements = obj.elements; | |
| if (key == "length") return make_node_from_constant(elements.length, obj); | |
| if (typeof key == "number" && key in elements) value = elements[key]; | |
| } else if (obj instanceof AST_Object) { | |
| key = "" + key; | |
| var props = obj.properties; | |
| for (var i = props.length; --i >= 0;) { | |
| var prop = props[i]; | |
| if (!(prop instanceof AST_ObjectKeyVal)) return; | |
| if (!value && props[i].key === key) value = props[i].value; | |
| } | |
| } | |
| return value instanceof AST_SymbolRef && value.fixed_value() || value; | |
| } | |
| export function has_break_or_continue(loop, parent) { | |
| var found = false; | |
| var tw = new TreeWalker(function(node) { | |
| if (found || node instanceof AST_Scope) return true; | |
| if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) { | |
| return found = true; | |
| } | |
| }); | |
| if (parent instanceof AST_LabeledStatement) tw.push(parent); | |
| tw.push(loop); | |
| loop.body.walk(tw); | |
| return found; | |
| } | |
| // we shouldn't compress (1,func)(something) to | |
| // func(something) because that changes the meaning of | |
| // the func (becomes lexical instead of global). | |
| export function maintain_this_binding(parent, orig, val) { | |
| if (requires_sequence_to_maintain_binding(parent, orig, val)) { | |
| const zero = make_node(AST_Number, orig, { value: 0 }); | |
| return make_sequence(orig, [ zero, val ]); | |
| } else { | |
| return val; | |
| } | |
| } | |
| /** Detect (1, x.noThis)(), (0, eval)(), which need sequences */ | |
| export function requires_sequence_to_maintain_binding(parent, orig, val) { | |
| return ( | |
| parent instanceof AST_UnaryPrefix && parent.operator == "delete" | |
| || parent instanceof AST_Call && parent.expression === orig | |
| && ( | |
| val instanceof AST_Chain | |
| || val instanceof AST_PropAccess | |
| || val instanceof AST_SymbolRef && val.name == "eval" | |
| ) | |
| ); | |
| } | |
| export function is_func_expr(node) { | |
| return node instanceof AST_Arrow || node instanceof AST_Function; | |
| } | |
| /** | |
| * Used to determine whether the node can benefit from negation. | |
| * Not the case with arrow functions (you need an extra set of parens). */ | |
| export function is_iife_call(node) { | |
| if (node.TYPE != "Call") return false; | |
| return node.expression instanceof AST_Function || is_iife_call(node.expression); | |
| } | |
| export function is_empty(thing) { | |
| if (thing === null) return true; | |
| if (thing instanceof AST_EmptyStatement) return true; | |
| if (thing instanceof AST_BlockStatement) return thing.body.length == 0; | |
| return false; | |
| } | |
| export const identifier_atom = makePredicate("Infinity NaN undefined"); | |
| export function is_identifier_atom(node) { | |
| return node instanceof AST_Infinity | |
| || node instanceof AST_NaN | |
| || node instanceof AST_Undefined; | |
| } | |
| /** Check if this is a SymbolRef node which has one def of a certain AST type */ | |
| export function is_ref_of(ref, type) { | |
| if (!(ref instanceof AST_SymbolRef)) return false; | |
| var orig = ref.definition().orig; | |
| for (var i = orig.length; --i >= 0;) { | |
| if (orig[i] instanceof type) return true; | |
| } | |
| } | |
| /**Can we turn { block contents... } into just the block contents ? | |
| * Not if one of these is inside. | |
| **/ | |
| export function can_be_evicted_from_block(node) { | |
| return !( | |
| node instanceof AST_DefClass || | |
| node instanceof AST_Defun || | |
| node instanceof AST_Let || | |
| node instanceof AST_Const || | |
| node instanceof AST_Export || | |
| node instanceof AST_Import | |
| ); | |
| } | |
| export function as_statement_array(thing) { | |
| if (thing === null) return []; | |
| if (thing instanceof AST_BlockStatement) return thing.body; | |
| if (thing instanceof AST_EmptyStatement) return []; | |
| if (thing instanceof AST_Statement) return [ thing ]; | |
| throw new Error("Can't convert thing to statement array"); | |
| } | |
| export function is_reachable(scope_node, defs) { | |
| const find_ref = node => { | |
| if (node instanceof AST_SymbolRef && defs.includes(node.definition())) { | |
| return walk_abort; | |
| } | |
| }; | |
| return walk_parent(scope_node, (node, info) => { | |
| if (node instanceof AST_Scope && node !== scope_node) { | |
| var parent = info.parent(); | |
| if ( | |
| parent instanceof AST_Call | |
| && parent.expression === node | |
| // Async/Generators aren't guaranteed to sync evaluate all of | |
| // their body steps, so it's possible they close over the variable. | |
| && !(node.async || node.is_generator) | |
| ) { | |
| return; | |
| } | |
| if (walk(node, find_ref)) return walk_abort; | |
| return true; | |
| } | |
| }); | |
| } | |
| /** Check if a ref refers to the name of a function/class it's defined within */ | |
| export function is_recursive_ref(tw, def) { | |
| var node; | |
| for (var i = 0; node = tw.parent(i); i++) { | |
| if (node instanceof AST_Lambda || node instanceof AST_Class) { | |
| var name = node.name; | |
| if (name && name.definition() === def) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| // TODO this only works with AST_Defun, shouldn't it work for other ways of defining functions? | |
| export function retain_top_func(fn, compressor) { | |
| return compressor.top_retain | |
| && fn instanceof AST_Defun | |
| && has_flag(fn, TOP) | |
| && fn.name | |
| && compressor.top_retain(fn.name.definition()); | |
| } | |
Xet Storage Details
- Size:
- 11.9 kB
- Xet hash:
- 0cb0223d5907500c16e78ae3d79a2ef650c4fcf98332c5a68f6587e322d4a2da
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.