mangleString.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var esprima = require('esprima');
  20. var escodegen = require('escodegen');
  21. var estraverse = require('estraverse');
  22. var SYNTAX = estraverse.Syntax;
  23. var STR_MIN_LENGTH = 5;
  24. var STR_MIN_DIST = 1000;
  25. var STR_MIN_COUNT = 2;
  26. function createDeclaration(declarations) {
  27. return {
  28. type: SYNTAX.VariableDeclaration,
  29. declarations: declarations,
  30. kind: 'var'
  31. };
  32. }
  33. function createDeclarator(id, init) {
  34. return {
  35. type: SYNTAX.VariableDeclarator,
  36. id: {
  37. type: SYNTAX.Identifier,
  38. name: id
  39. },
  40. init: {
  41. type: SYNTAX.Literal,
  42. value: init
  43. }
  44. };
  45. }
  46. function base54Digits() {
  47. return 'etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984';
  48. }
  49. var base54 = (function(){
  50. var DIGITS = base54Digits();
  51. return function(num) {
  52. var ret = '';
  53. var base = 54;
  54. do {
  55. ret += DIGITS.charAt(num % base);
  56. num = Math.floor(num / base);
  57. base = 64;
  58. } while (num > 0);
  59. return ret;
  60. };
  61. })();
  62. function mangleString(source) {
  63. var ast = esprima.parse(source, {
  64. loc: true
  65. });
  66. var stringVariables = {};
  67. var stringRelaceCount = 0;
  68. estraverse.traverse(ast, {
  69. enter: function (node, parent) {
  70. if (node.type === SYNTAX.Literal
  71. && typeof node.value === 'string'
  72. ) {
  73. // Ignore if string is the key of property
  74. if (parent.type === SYNTAX.Property) {
  75. return;
  76. }
  77. var value = node.value;
  78. if (value.length > STR_MIN_LENGTH) {
  79. if (!stringVariables[value]) {
  80. stringVariables[value] = {
  81. count: 0,
  82. lastLoc: node.loc.start.line,
  83. name: '__echartsString__' + base54(stringRelaceCount++)
  84. };
  85. }
  86. var diff = node.loc.start.line - stringVariables[value].lastLoc;
  87. // GZIP ?
  88. if (diff >= STR_MIN_DIST) {
  89. stringVariables[value].lastLoc = node.loc.start.line;
  90. stringVariables[value].count++;
  91. }
  92. }
  93. }
  94. if (node.type === SYNTAX.MemberExpression && !node.computed) {
  95. if (node.property.type === SYNTAX.Identifier) {
  96. var value = node.property.name;
  97. if (value.length > STR_MIN_LENGTH) {
  98. if (!stringVariables[value]) {
  99. stringVariables[value] = {
  100. count: 0,
  101. lastLoc: node.loc.start.line,
  102. name: '__echartsString__' + base54(stringRelaceCount++)
  103. };
  104. }
  105. var diff = node.loc.start.line - stringVariables[value].lastLoc;
  106. if (diff >= STR_MIN_DIST) {
  107. stringVariables[value].lastLoc = node.loc.start.line;
  108. stringVariables[value].count++;
  109. }
  110. }
  111. }
  112. }
  113. }
  114. });
  115. estraverse.replace(ast, {
  116. enter: function (node, parent) {
  117. if ((node.type === SYNTAX.Literal
  118. && typeof node.value === 'string')
  119. ) {
  120. // Ignore if string is the key of property
  121. if (parent.type === SYNTAX.Property) {
  122. return;
  123. }
  124. var str = node.value;
  125. if (stringVariables[str] && stringVariables[str].count > STR_MIN_COUNT) {
  126. return {
  127. type: SYNTAX.Identifier,
  128. name: stringVariables[str].name
  129. };
  130. }
  131. }
  132. if (node.type === SYNTAX.MemberExpression && !node.computed) {
  133. if (node.property.type === SYNTAX.Identifier) {
  134. var str = node.property.name;
  135. if (stringVariables[str] && stringVariables[str].count > STR_MIN_COUNT) {
  136. return {
  137. type: SYNTAX.MemberExpression,
  138. object: node.object,
  139. property: {
  140. type: SYNTAX.Identifier,
  141. name: stringVariables[str].name
  142. },
  143. computed: true
  144. };
  145. }
  146. }
  147. }
  148. }
  149. });
  150. // Add variables in the top
  151. for (var str in stringVariables) {
  152. // Used more than once
  153. if (stringVariables[str].count > STR_MIN_COUNT) {
  154. ast.body.unshift(createDeclaration([
  155. createDeclarator(stringVariables[str].name, str)
  156. ]));
  157. }
  158. }
  159. return escodegen.generate(
  160. ast,
  161. {
  162. format: {escapeless: true},
  163. comment: true
  164. }
  165. );
  166. }
  167. exports = module.exports = mangleString;