size.js 12 KB

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