506 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			506 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {
 | |
|     AST_Accessor,
 | |
|     AST_Array,
 | |
|     AST_Arrow,
 | |
|     AST_Await,
 | |
|     AST_BigInt,
 | |
|     AST_Binary,
 | |
|     AST_Block,
 | |
|     AST_Break,
 | |
|     AST_Call,
 | |
|     AST_Case,
 | |
|     AST_Class,
 | |
|     AST_ClassStaticBlock,
 | |
|     AST_ClassPrivateProperty,
 | |
|     AST_ClassProperty,
 | |
|     AST_ConciseMethod,
 | |
|     AST_Conditional,
 | |
|     AST_Const,
 | |
|     AST_Continue,
 | |
|     AST_Debugger,
 | |
|     AST_Default,
 | |
|     AST_Defun,
 | |
|     AST_Destructuring,
 | |
|     AST_Directive,
 | |
|     AST_Do,
 | |
|     AST_Dot,
 | |
|     AST_DotHash,
 | |
|     AST_EmptyStatement,
 | |
|     AST_Expansion,
 | |
|     AST_Export,
 | |
|     AST_False,
 | |
|     AST_For,
 | |
|     AST_ForIn,
 | |
|     AST_Function,
 | |
|     AST_Hole,
 | |
|     AST_If,
 | |
|     AST_Import,
 | |
|     AST_ImportMeta,
 | |
|     AST_Infinity,
 | |
|     AST_LabeledStatement,
 | |
|     AST_Let,
 | |
|     AST_NameMapping,
 | |
|     AST_NaN,
 | |
|     AST_New,
 | |
|     AST_NewTarget,
 | |
|     AST_Node,
 | |
|     AST_Null,
 | |
|     AST_Number,
 | |
|     AST_Object,
 | |
|     AST_ObjectKeyVal,
 | |
|     AST_ObjectGetter,
 | |
|     AST_ObjectSetter,
 | |
|     AST_PrivateGetter,
 | |
|     AST_PrivateMethod,
 | |
|     AST_PrivateSetter,
 | |
|     AST_PrivateIn,
 | |
|     AST_RegExp,
 | |
|     AST_Return,
 | |
|     AST_Sequence,
 | |
|     AST_String,
 | |
|     AST_Sub,
 | |
|     AST_Super,
 | |
|     AST_Switch,
 | |
|     AST_Symbol,
 | |
|     AST_SymbolClassProperty,
 | |
|     AST_SymbolExportForeign,
 | |
|     AST_SymbolImportForeign,
 | |
|     AST_SymbolRef,
 | |
|     AST_SymbolDeclaration,
 | |
|     AST_TemplateSegment,
 | |
|     AST_TemplateString,
 | |
|     AST_This,
 | |
|     AST_Throw,
 | |
|     AST_Toplevel,
 | |
|     AST_True,
 | |
|     AST_Try,
 | |
|     AST_Catch,
 | |
|     AST_Finally,
 | |
|     AST_Unary,
 | |
|     AST_Undefined,
 | |
|     AST_Using,
 | |
|     AST_Var,
 | |
|     AST_VarDefLike,
 | |
|     AST_While,
 | |
|     AST_With,
 | |
|     AST_Yield,
 | |
|     walk_parent
 | |
| } from "./ast.js";
 | |
| import { first_in_statement } from "./utils/first_in_statement.js";
 | |
| 
 | |
| let mangle_options = undefined;
 | |
| AST_Node.prototype.size = function (compressor, stack) {
 | |
|     mangle_options = compressor && compressor._mangle_options;
 | |
| 
 | |
|     let size = 0;
 | |
|     walk_parent(this, (node, info) => {
 | |
|         size += node._size(info);
 | |
| 
 | |
|         // Braceless arrow functions have fake "return" statements
 | |
|         if (node instanceof AST_Arrow && node.is_braceless()) {
 | |
|             size += node.body[0].value._size(info);
 | |
|             return true;
 | |
|         }
 | |
|     }, stack || (compressor && compressor.stack));
 | |
| 
 | |
|     // just to save a bit of memory
 | |
|     mangle_options = undefined;
 | |
| 
 | |
|     return size;
 | |
| };
 | |
| 
 | |
| AST_Node.prototype._size = () => 0;
 | |
| 
 | |
| AST_Debugger.prototype._size = () => 8;
 | |
| 
 | |
| AST_Directive.prototype._size = function () {
 | |
|     // TODO string encoding stuff
 | |
|     return 2 + this.value.length;
 | |
| };
 | |
| 
 | |
| /** Count commas/semicolons necessary to show a list of expressions/statements */
 | |
| const list_overhead = (array) => array.length && array.length - 1;
 | |
| 
 | |
| AST_Block.prototype._size = function () {
 | |
|     return 2 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Toplevel.prototype._size = function() {
 | |
|     return list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_EmptyStatement.prototype._size = () => 1;
 | |
| 
 | |
| AST_LabeledStatement.prototype._size = () => 2;  // x:
 | |
| 
 | |
| AST_Do.prototype._size = () => 9;
 | |
| 
 | |
| AST_While.prototype._size = () => 7;
 | |
| 
 | |
| AST_For.prototype._size = () => 8;
 | |
| 
 | |
| AST_ForIn.prototype._size = () => 8;
 | |
| // AST_ForOf inherits ^
 | |
| 
 | |
| AST_With.prototype._size = () => 6;
 | |
| 
 | |
| AST_Expansion.prototype._size = () => 3;
 | |
| 
 | |
| const lambda_modifiers = func =>
 | |
|     (func.is_generator ? 1 : 0) + (func.async ? 6 : 0);
 | |
| 
 | |
| AST_Accessor.prototype._size = function () {
 | |
|     return lambda_modifiers(this) + 4 + list_overhead(this.argnames) + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Function.prototype._size = function (info) {
 | |
|     const first = !!first_in_statement(info);
 | |
|     return (first * 2) + lambda_modifiers(this) + 12 + list_overhead(this.argnames) + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Defun.prototype._size = function () {
 | |
|     return lambda_modifiers(this) + 13 + list_overhead(this.argnames) + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Arrow.prototype._size = function () {
 | |
|     let args_and_arrow = 2 + list_overhead(this.argnames);
 | |
| 
 | |
|     if (
 | |
|         !(
 | |
|             this.argnames.length === 1
 | |
|             && this.argnames[0] instanceof AST_Symbol
 | |
|         )
 | |
|     ) {
 | |
|         args_and_arrow += 2; // parens around the args
 | |
|     }
 | |
| 
 | |
|     const body_overhead = this.is_braceless() ? 0 : list_overhead(this.body) + 2;
 | |
| 
 | |
|     return lambda_modifiers(this) + args_and_arrow + body_overhead;
 | |
| };
 | |
| 
 | |
| AST_Destructuring.prototype._size = () => 2;
 | |
| 
 | |
| AST_TemplateString.prototype._size = function () {
 | |
|     return 2 + (Math.floor(this.segments.length / 2) * 3);  /* "${}" */
 | |
| };
 | |
| 
 | |
| AST_TemplateSegment.prototype._size = function () {
 | |
|     return this.value.length;
 | |
| };
 | |
| 
 | |
| AST_Return.prototype._size = function () {
 | |
|     return this.value ? 7 : 6;
 | |
| };
 | |
| 
 | |
| AST_Throw.prototype._size = () => 6;
 | |
| 
 | |
| AST_Break.prototype._size = function () {
 | |
|     return this.label ? 6 : 5;
 | |
| };
 | |
| 
 | |
| AST_Continue.prototype._size = function () {
 | |
|     return this.label ? 9 : 8;
 | |
| };
 | |
| 
 | |
| AST_If.prototype._size = () => 4;
 | |
| 
 | |
| AST_Switch.prototype._size = function () {
 | |
|     return 8 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Case.prototype._size = function () {
 | |
|     return 5 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Default.prototype._size = function () {
 | |
|     return 8 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Try.prototype._size = () => 3;
 | |
| 
 | |
| AST_Catch.prototype._size = function () {
 | |
|     let size = 7 + list_overhead(this.body);
 | |
|     if (this.argname) {
 | |
|         size += 2;
 | |
|     }
 | |
|     return size;
 | |
| };
 | |
| 
 | |
| AST_Finally.prototype._size = function () {
 | |
|     return 7 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_Var.prototype._size = function () {
 | |
|     return 4 + list_overhead(this.definitions);
 | |
| };
 | |
| 
 | |
| AST_Let.prototype._size = function () {
 | |
|     return 4 + list_overhead(this.definitions);
 | |
| };
 | |
| 
 | |
| AST_Const.prototype._size = function () {
 | |
|     return 6 + list_overhead(this.definitions);
 | |
| };
 | |
| 
 | |
| AST_Using.prototype._size = function () {
 | |
|     const await_size = this.await ? 6 : 0;
 | |
|     return await_size + 6 + list_overhead(this.definitions);
 | |
| };
 | |
| 
 | |
| AST_VarDefLike.prototype._size = function () {
 | |
|     return this.value ? 1 : 0;
 | |
| };
 | |
| 
 | |
| AST_NameMapping.prototype._size = function () {
 | |
|     // foreign name isn't mangled
 | |
|     return this.name ? 4 : 0;
 | |
| };
 | |
| 
 | |
| AST_Import.prototype._size = function () {
 | |
|     // import
 | |
|     let size = 6;
 | |
| 
 | |
|     if (this.imported_name) size += 1;
 | |
| 
 | |
|     // from
 | |
|     if (this.imported_name || this.imported_names) size += 5;
 | |
| 
 | |
|     // braces, and the commas
 | |
|     if (this.imported_names) {
 | |
|         size += 2 + list_overhead(this.imported_names);
 | |
|     }
 | |
| 
 | |
|     return size;
 | |
| };
 | |
| 
 | |
| AST_ImportMeta.prototype._size = () => 11;
 | |
| 
 | |
| AST_Export.prototype._size = function () {
 | |
|     let size = 7 + (this.is_default ? 8 : 0);
 | |
| 
 | |
|     if (this.exported_value) {
 | |
|         size += this.exported_value._size();
 | |
|     }
 | |
| 
 | |
|     if (this.exported_names) {
 | |
|         // Braces and commas
 | |
|         size += 2 + list_overhead(this.exported_names);
 | |
|     }
 | |
| 
 | |
|     if (this.module_name) {
 | |
|         // "from "
 | |
|         size += 5;
 | |
|     }
 | |
| 
 | |
|     return size;
 | |
| };
 | |
| 
 | |
| AST_Call.prototype._size = function () {
 | |
|     if (this.optional) {
 | |
|         return 4 + list_overhead(this.args);
 | |
|     }
 | |
|     return 2 + list_overhead(this.args);
 | |
| };
 | |
| 
 | |
| AST_New.prototype._size = function () {
 | |
|     return 6 + list_overhead(this.args);
 | |
| };
 | |
| 
 | |
| AST_Sequence.prototype._size = function () {
 | |
|     return list_overhead(this.expressions);
 | |
| };
 | |
| 
 | |
| AST_Dot.prototype._size = function () {
 | |
|     if (this.optional) {
 | |
|         return this.property.length + 2;
 | |
|     }
 | |
|     return this.property.length + 1;
 | |
| };
 | |
| 
 | |
| AST_DotHash.prototype._size = function () {
 | |
|     if (this.optional) {
 | |
|         return this.property.length + 3;
 | |
|     }
 | |
|     return this.property.length + 2;
 | |
| };
 | |
| 
 | |
| AST_Sub.prototype._size = function () {
 | |
|     return this.optional ? 4 : 2;
 | |
| };
 | |
| 
 | |
| AST_Unary.prototype._size = function () {
 | |
|     if (this.operator === "typeof") return 7;
 | |
|     if (this.operator === "void") return 5;
 | |
|     return this.operator.length;
 | |
| };
 | |
| 
 | |
| AST_Binary.prototype._size = function (info) {
 | |
|     if (this.operator === "in") return 4;
 | |
| 
 | |
|     let size = this.operator.length;
 | |
| 
 | |
|     if (
 | |
|         (this.operator === "+" || this.operator === "-")
 | |
|         && this.right instanceof AST_Unary && this.right.operator === this.operator
 | |
|     ) {
 | |
|         // 1+ +a > needs space between the +
 | |
|         size += 1;
 | |
|     }
 | |
| 
 | |
|     if (this.needs_parens(info)) {
 | |
|         size += 2;
 | |
|     }
 | |
| 
 | |
|     return size;
 | |
| };
 | |
| 
 | |
| AST_Conditional.prototype._size = () => 3;
 | |
| 
 | |
| AST_Array.prototype._size = function () {
 | |
|     return 2 + list_overhead(this.elements);
 | |
| };
 | |
| 
 | |
| AST_Object.prototype._size = function (info) {
 | |
|     let base = 2;
 | |
|     if (first_in_statement(info)) {
 | |
|         base += 2; // parens
 | |
|     }
 | |
|     return base + list_overhead(this.properties);
 | |
| };
 | |
| 
 | |
| /*#__INLINE__*/
 | |
| const key_size = key =>
 | |
|     typeof key === "string" ? key.length : 0;
 | |
| 
 | |
| AST_ObjectKeyVal.prototype._size = function () {
 | |
|     return key_size(this.key) + 1;
 | |
| };
 | |
| 
 | |
| /*#__INLINE__*/
 | |
| const static_size = is_static => is_static ? 7 : 0;
 | |
| 
 | |
| AST_ObjectGetter.prototype._size = function () {
 | |
|     return 5 + static_size(this.static) + key_size(this.key);
 | |
| };
 | |
| 
 | |
| AST_ObjectSetter.prototype._size = function () {
 | |
|     return 5 + static_size(this.static) + key_size(this.key);
 | |
| };
 | |
| 
 | |
| AST_ConciseMethod.prototype._size = function () {
 | |
|     return static_size(this.static) + key_size(this.key);
 | |
| };
 | |
| 
 | |
| AST_PrivateMethod.prototype._size = function () {
 | |
|     return AST_ConciseMethod.prototype._size.call(this) + 1;
 | |
| };
 | |
| 
 | |
| AST_PrivateGetter.prototype._size = function () {
 | |
|     return AST_ConciseMethod.prototype._size.call(this) + 4;
 | |
| };
 | |
| 
 | |
| AST_PrivateSetter.prototype._size = function () {
 | |
|     return AST_ConciseMethod.prototype._size.call(this) + 4;
 | |
| };
 | |
| 
 | |
| AST_PrivateIn.prototype._size = function () {
 | |
|     return 5; // "#", and " in "
 | |
| };
 | |
| 
 | |
| AST_Class.prototype._size = function () {
 | |
|     return (
 | |
|         (this.name ? 8 : 7)
 | |
|         + (this.extends ? 8 : 0)
 | |
|     );
 | |
| };
 | |
| 
 | |
| AST_ClassStaticBlock.prototype._size = function () {
 | |
|     // "static{}" + semicolons
 | |
|     return 8 + list_overhead(this.body);
 | |
| };
 | |
| 
 | |
| AST_ClassProperty.prototype._size = function () {
 | |
|     return (
 | |
|         static_size(this.static)
 | |
|         + (typeof this.key === "string" ? this.key.length + 2 : 0)
 | |
|         + (this.value ? 1 : 0)
 | |
|     );
 | |
| };
 | |
| 
 | |
| AST_ClassPrivateProperty.prototype._size = function () {
 | |
|     return AST_ClassProperty.prototype._size.call(this) + 1;
 | |
| };
 | |
| 
 | |
| AST_Symbol.prototype._size = function () {
 | |
|     if (!(mangle_options && this.thedef && !this.thedef.unmangleable(mangle_options))) {
 | |
|         return this.name.length;
 | |
|     } else {
 | |
|         return 1;
 | |
|     }
 | |
| };
 | |
| 
 | |
| // TODO take propmangle into account
 | |
| AST_SymbolClassProperty.prototype._size = function () {
 | |
|     return this.name.length;
 | |
| };
 | |
| 
 | |
| AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () {
 | |
|     if (this.name === "arguments") return 9;
 | |
| 
 | |
|     return AST_Symbol.prototype._size.call(this);
 | |
| };
 | |
| 
 | |
| AST_NewTarget.prototype._size = () => 10;
 | |
| 
 | |
| AST_SymbolImportForeign.prototype._size = function () {
 | |
|     return this.name.length;
 | |
| };
 | |
| 
 | |
| AST_SymbolExportForeign.prototype._size = function () {
 | |
|     return this.name.length;
 | |
| };
 | |
| 
 | |
| AST_This.prototype._size = () => 4;
 | |
| 
 | |
| AST_Super.prototype._size = () => 5;
 | |
| 
 | |
| AST_String.prototype._size = function () {
 | |
|     return this.value.length + 2;
 | |
| };
 | |
| 
 | |
| AST_Number.prototype._size = function () {
 | |
|     const { value } = this;
 | |
|     if (value === 0) return 1;
 | |
|     if (value > 0 && Math.floor(value) === value) {
 | |
|         return Math.floor(Math.log10(value) + 1);
 | |
|     }
 | |
|     return value.toString().length;
 | |
| };
 | |
| 
 | |
| AST_BigInt.prototype._size = function () {
 | |
|     return this.value.length;
 | |
| };
 | |
| 
 | |
| AST_RegExp.prototype._size = function () {
 | |
|     return this.value.toString().length;
 | |
| };
 | |
| 
 | |
| AST_Null.prototype._size = () => 4;
 | |
| 
 | |
| AST_NaN.prototype._size = () => 3;
 | |
| 
 | |
| AST_Undefined.prototype._size = () => 6; // "void 0"
 | |
| 
 | |
| AST_Hole.prototype._size = () => 0;  // comma is taken into account by list_overhead()
 | |
| 
 | |
| AST_Infinity.prototype._size = () => 8;
 | |
| 
 | |
| AST_True.prototype._size = () => 4;
 | |
| 
 | |
| AST_False.prototype._size = () => 5;
 | |
| 
 | |
| AST_Await.prototype._size = () => 6;
 | |
| 
 | |
| AST_Yield.prototype._size = () => 6;
 |