size.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. import {
  2. AST_Accessor,
  3. AST_Array,
  4. AST_Arrow,
  5. AST_Await,
  6. AST_BigInt,
  7. AST_Binary,
  8. AST_Block,
  9. AST_Break,
  10. AST_Call,
  11. AST_Case,
  12. AST_Class,
  13. AST_ClassProperty,
  14. AST_ConciseMethod,
  15. AST_Conditional,
  16. AST_Const,
  17. AST_Continue,
  18. AST_Debugger,
  19. AST_Default,
  20. AST_Defun,
  21. AST_Destructuring,
  22. AST_Directive,
  23. AST_Do,
  24. AST_Dot,
  25. AST_EmptyStatement,
  26. AST_Expansion,
  27. AST_Export,
  28. AST_False,
  29. AST_For,
  30. AST_ForIn,
  31. AST_Function,
  32. AST_Hole,
  33. AST_If,
  34. AST_Import,
  35. AST_ImportMeta,
  36. AST_Infinity,
  37. AST_LabeledStatement,
  38. AST_Let,
  39. AST_NameMapping,
  40. AST_NaN,
  41. AST_New,
  42. AST_NewTarget,
  43. AST_Node,
  44. AST_Null,
  45. AST_Number,
  46. AST_Object,
  47. AST_ObjectKeyVal,
  48. AST_ObjectGetter,
  49. AST_ObjectSetter,
  50. AST_RegExp,
  51. AST_Return,
  52. AST_Sequence,
  53. AST_String,
  54. AST_Sub,
  55. AST_Super,
  56. AST_Switch,
  57. AST_Symbol,
  58. AST_SymbolClassProperty,
  59. AST_SymbolExportForeign,
  60. AST_SymbolImportForeign,
  61. AST_SymbolRef,
  62. AST_SymbolDeclaration,
  63. AST_TemplateSegment,
  64. AST_TemplateString,
  65. AST_This,
  66. AST_Throw,
  67. AST_Toplevel,
  68. AST_True,
  69. AST_Try,
  70. AST_Catch,
  71. AST_Finally,
  72. AST_Unary,
  73. AST_Undefined,
  74. AST_Var,
  75. AST_VarDef,
  76. AST_While,
  77. AST_With,
  78. AST_Yield,
  79. walk_parent
  80. } from "./ast.js";
  81. import { first_in_statement } from "./utils/first_in_statement.js";
  82. let mangle_options = undefined;
  83. AST_Node.prototype.size = function (compressor, stack) {
  84. mangle_options = compressor && compressor.mangle_options;
  85. let size = 0;
  86. walk_parent(this, (node, info) => {
  87. size += node._size(info);
  88. }, stack || (compressor && compressor.stack));
  89. // just to save a bit of memory
  90. mangle_options = undefined;
  91. return size;
  92. };
  93. AST_Node.prototype._size = () => 0;
  94. AST_Debugger.prototype._size = () => 8;
  95. AST_Directive.prototype._size = function () {
  96. // TODO string encoding stuff
  97. return 2 + this.value.length;
  98. };
  99. const list_overhead = (array) => array.length && array.length - 1;
  100. AST_Block.prototype._size = function () {
  101. return 2 + list_overhead(this.body);
  102. };
  103. AST_Toplevel.prototype._size = function() {
  104. return list_overhead(this.body);
  105. };
  106. AST_EmptyStatement.prototype._size = () => 1;
  107. AST_LabeledStatement.prototype._size = () => 2; // x:
  108. AST_Do.prototype._size = () => 9;
  109. AST_While.prototype._size = () => 7;
  110. AST_For.prototype._size = () => 8;
  111. AST_ForIn.prototype._size = () => 8;
  112. // AST_ForOf inherits ^
  113. AST_With.prototype._size = () => 6;
  114. AST_Expansion.prototype._size = () => 3;
  115. /*#__INLINE__*/
  116. const lambda_modifiers = func =>
  117. (func.is_generator ? 1 : 0) + (func.async ? 6 : 0);
  118. AST_Accessor.prototype._size = function () {
  119. return lambda_modifiers(this) + 4 + list_overhead(this.argnames) + list_overhead(this.body);
  120. };
  121. AST_Function.prototype._size = function (info) {
  122. const first = !!first_in_statement(info);
  123. return (first * 2) + lambda_modifiers(this) + 12 + list_overhead(this.argnames) + list_overhead(this.body);
  124. };
  125. AST_Defun.prototype._size = function () {
  126. return lambda_modifiers(this) + 13 + list_overhead(this.argnames) + list_overhead(this.body);
  127. };
  128. AST_Arrow.prototype._size = function () {
  129. let args_and_arrow = 2 + list_overhead(this.argnames);
  130. if (
  131. !(
  132. this.argnames.length === 1
  133. && this.argnames[0] instanceof AST_Symbol
  134. )
  135. ) {
  136. args_and_arrow += 2;
  137. }
  138. return lambda_modifiers(this) + args_and_arrow + (Array.isArray(this.body) ? list_overhead(this.body) : this.body._size());
  139. };
  140. AST_Destructuring.prototype._size = () => 2;
  141. AST_TemplateString.prototype._size = function () {
  142. return 2 + (Math.floor(this.segments.length / 2) * 3); /* "${}" */
  143. };
  144. AST_TemplateSegment.prototype._size = function () {
  145. return this.value.length;
  146. };
  147. AST_Return.prototype._size = function () {
  148. return this.value ? 7 : 6;
  149. };
  150. AST_Throw.prototype._size = () => 6;
  151. AST_Break.prototype._size = function () {
  152. return this.label ? 6 : 5;
  153. };
  154. AST_Continue.prototype._size = function () {
  155. return this.label ? 9 : 8;
  156. };
  157. AST_If.prototype._size = () => 4;
  158. AST_Switch.prototype._size = function () {
  159. return 8 + list_overhead(this.body);
  160. };
  161. AST_Case.prototype._size = function () {
  162. return 5 + list_overhead(this.body);
  163. };
  164. AST_Default.prototype._size = function () {
  165. return 8 + list_overhead(this.body);
  166. };
  167. AST_Try.prototype._size = function () {
  168. return 3 + list_overhead(this.body);
  169. };
  170. AST_Catch.prototype._size = function () {
  171. let size = 7 + list_overhead(this.body);
  172. if (this.argname) {
  173. size += 2;
  174. }
  175. return size;
  176. };
  177. AST_Finally.prototype._size = function () {
  178. return 7 + list_overhead(this.body);
  179. };
  180. /*#__INLINE__*/
  181. const def_size = (size, def) => size + list_overhead(def.definitions);
  182. AST_Var.prototype._size = function () {
  183. return def_size(4, this);
  184. };
  185. AST_Let.prototype._size = function () {
  186. return def_size(4, this);
  187. };
  188. AST_Const.prototype._size = function () {
  189. return def_size(6, this);
  190. };
  191. AST_VarDef.prototype._size = function () {
  192. return this.value ? 1 : 0;
  193. };
  194. AST_NameMapping.prototype._size = function () {
  195. // foreign name isn't mangled
  196. return this.name ? 4 : 0;
  197. };
  198. AST_Import.prototype._size = function () {
  199. // import
  200. let size = 6;
  201. if (this.imported_name) size += 1;
  202. // from
  203. if (this.imported_name || this.imported_names) size += 5;
  204. // braces, and the commas
  205. if (this.imported_names) {
  206. size += 2 + list_overhead(this.imported_names);
  207. }
  208. return size;
  209. };
  210. AST_ImportMeta.prototype._size = () => 11;
  211. AST_Export.prototype._size = function () {
  212. let size = 7 + (this.is_default ? 8 : 0);
  213. if (this.exported_value) {
  214. size += this.exported_value._size();
  215. }
  216. if (this.exported_names) {
  217. // Braces and commas
  218. size += 2 + list_overhead(this.exported_names);
  219. }
  220. if (this.module_name) {
  221. // "from "
  222. size += 5;
  223. }
  224. return size;
  225. };
  226. AST_Call.prototype._size = function () {
  227. if (this.optional) {
  228. return 4 + list_overhead(this.args);
  229. }
  230. return 2 + list_overhead(this.args);
  231. };
  232. AST_New.prototype._size = function () {
  233. return 6 + list_overhead(this.args);
  234. };
  235. AST_Sequence.prototype._size = function () {
  236. return list_overhead(this.expressions);
  237. };
  238. AST_Dot.prototype._size = function () {
  239. if (this.optional) {
  240. return this.property.length + 2;
  241. }
  242. return this.property.length + 1;
  243. };
  244. AST_Sub.prototype._size = function () {
  245. return this.optional ? 4 : 2;
  246. };
  247. AST_Unary.prototype._size = function () {
  248. if (this.operator === "typeof") return 7;
  249. if (this.operator === "void") return 5;
  250. return this.operator.length;
  251. };
  252. AST_Binary.prototype._size = function (info) {
  253. if (this.operator === "in") return 4;
  254. let size = this.operator.length;
  255. if (
  256. (this.operator === "+" || this.operator === "-")
  257. && this.right instanceof AST_Unary && this.right.operator === this.operator
  258. ) {
  259. // 1+ +a > needs space between the +
  260. size += 1;
  261. }
  262. if (this.needs_parens(info)) {
  263. size += 2;
  264. }
  265. return size;
  266. };
  267. AST_Conditional.prototype._size = () => 3;
  268. AST_Array.prototype._size = function () {
  269. return 2 + list_overhead(this.elements);
  270. };
  271. AST_Object.prototype._size = function (info) {
  272. let base = 2;
  273. if (first_in_statement(info)) {
  274. base += 2; // parens
  275. }
  276. return base + list_overhead(this.properties);
  277. };
  278. /*#__INLINE__*/
  279. const key_size = key =>
  280. typeof key === "string" ? key.length : 0;
  281. AST_ObjectKeyVal.prototype._size = function () {
  282. return key_size(this.key) + 1;
  283. };
  284. /*#__INLINE__*/
  285. const static_size = is_static => is_static ? 7 : 0;
  286. AST_ObjectGetter.prototype._size = function () {
  287. return 5 + static_size(this.static) + key_size(this.key);
  288. };
  289. AST_ObjectSetter.prototype._size = function () {
  290. return 5 + static_size(this.static) + key_size(this.key);
  291. };
  292. AST_ConciseMethod.prototype._size = function () {
  293. return static_size(this.static) + key_size(this.key) + lambda_modifiers(this);
  294. };
  295. AST_Class.prototype._size = function () {
  296. return (
  297. (this.name ? 8 : 7)
  298. + (this.extends ? 8 : 0)
  299. );
  300. };
  301. AST_ClassProperty.prototype._size = function () {
  302. return (
  303. static_size(this.static)
  304. + (typeof this.key === "string" ? this.key.length + 2 : 0)
  305. + (this.value ? 1 : 0)
  306. );
  307. };
  308. AST_Symbol.prototype._size = function () {
  309. return !mangle_options || this.definition().unmangleable(mangle_options)
  310. ? this.name.length
  311. : 1;
  312. };
  313. // TODO take propmangle into account
  314. AST_SymbolClassProperty.prototype._size = function () {
  315. return this.name.length;
  316. };
  317. AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () {
  318. const { name, thedef } = this;
  319. if (thedef && thedef.global) return name.length;
  320. if (name === "arguments") return 9;
  321. return AST_Symbol.prototype._size.call(this);
  322. };
  323. AST_NewTarget.prototype._size = () => 10;
  324. AST_SymbolImportForeign.prototype._size = function () {
  325. return this.name.length;
  326. };
  327. AST_SymbolExportForeign.prototype._size = function () {
  328. return this.name.length;
  329. };
  330. AST_This.prototype._size = () => 4;
  331. AST_Super.prototype._size = () => 5;
  332. AST_String.prototype._size = function () {
  333. return this.value.length + 2;
  334. };
  335. AST_Number.prototype._size = function () {
  336. const { value } = this;
  337. if (value === 0) return 1;
  338. if (value > 0 && Math.floor(value) === value) {
  339. return Math.floor(Math.log10(value) + 1);
  340. }
  341. return value.toString().length;
  342. };
  343. AST_BigInt.prototype._size = function () {
  344. return this.value.length;
  345. };
  346. AST_RegExp.prototype._size = function () {
  347. return this.value.toString().length;
  348. };
  349. AST_Null.prototype._size = () => 4;
  350. AST_NaN.prototype._size = () => 3;
  351. AST_Undefined.prototype._size = () => 6; // "void 0"
  352. AST_Hole.prototype._size = () => 0; // comma is taken into account
  353. AST_Infinity.prototype._size = () => 8;
  354. AST_True.prototype._size = () => 4;
  355. AST_False.prototype._size = () => 5;
  356. AST_Await.prototype._size = () => 6;
  357. AST_Yield.prototype._size = () => 6;