1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | "use strict";
|
45 |
|
46 | var builtins = function() {
|
47 | var names = new Dictionary();
|
48 |
|
49 | [
|
50 | "null",
|
51 | "true",
|
52 | "false",
|
53 | "Infinity",
|
54 | "-Infinity",
|
55 | "undefined",
|
56 | ].forEach(add);
|
57 | [
|
58 | Array,
|
59 | Boolean,
|
60 | Date,
|
61 | Error,
|
62 | Function,
|
63 | Math,
|
64 | Number,
|
65 | Object,
|
66 | RegExp,
|
67 | String,
|
68 | ].forEach(function(ctor) {
|
69 | Object.getOwnPropertyNames(ctor).map(add);
|
70 | if (ctor.prototype) {
|
71 | Object.getOwnPropertyNames(new ctor()).map(add);
|
72 | Object.getOwnPropertyNames(ctor.prototype).map(add);
|
73 | }
|
74 | });
|
75 | return names;
|
76 |
|
77 | function add(name) {
|
78 | names.set(name, true);
|
79 | }
|
80 | }();
|
81 |
|
82 | function reserve_quoted_keys(ast, reserved) {
|
83 | ast.walk(new TreeWalker(function(node) {
|
84 | if (node instanceof AST_ClassProperty) {
|
85 | if (node.start && node.start.quote) add(node.key);
|
86 | } else if (node instanceof AST_ObjectProperty) {
|
87 | if (node.start && node.start.quote) add(node.key);
|
88 | } else if (node instanceof AST_Sub) {
|
89 | addStrings(node.property, add);
|
90 | }
|
91 | }));
|
92 |
|
93 | function add(name) {
|
94 | push_uniq(reserved, name);
|
95 | }
|
96 | }
|
97 |
|
98 | function addStrings(node, add) {
|
99 | if (node instanceof AST_Conditional) {
|
100 | addStrings(node.consequent, add);
|
101 | addStrings(node.alternative, add);
|
102 | } else if (node instanceof AST_Sequence) {
|
103 | addStrings(node.tail_node(), add);
|
104 | } else if (node instanceof AST_String) {
|
105 | add(node.value);
|
106 | }
|
107 | }
|
108 |
|
109 | function mangle_properties(ast, options) {
|
110 | options = defaults(options, {
|
111 | builtins: false,
|
112 | cache: null,
|
113 | debug: false,
|
114 | keep_quoted: false,
|
115 | regex: null,
|
116 | reserved: null,
|
117 | }, true);
|
118 |
|
119 | var reserved = options.builtins ? new Dictionary() : builtins.clone();
|
120 | if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
|
121 | reserved.set(name, true);
|
122 | });
|
123 |
|
124 | var cname = -1;
|
125 | var cache;
|
126 | if (options.cache) {
|
127 | cache = options.cache.props;
|
128 | cache.each(function(name) {
|
129 | reserved.set(name, true);
|
130 | });
|
131 | } else {
|
132 | cache = new Dictionary();
|
133 | }
|
134 |
|
135 | var regex = options.regex;
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | var debug = options.debug !== false;
|
141 | var debug_suffix;
|
142 | if (debug) debug_suffix = options.debug === true ? "" : options.debug;
|
143 |
|
144 | var names_to_mangle = new Dictionary();
|
145 | var unmangleable = reserved.clone();
|
146 |
|
147 |
|
148 | ast.walk(new TreeWalker(function(node) {
|
149 | if (node instanceof AST_Binary) {
|
150 | if (node.operator == "in") addStrings(node.left, add);
|
151 | } else if (node.TYPE == "Call") {
|
152 | var exp = node.expression;
|
153 | if (exp instanceof AST_Dot) switch (exp.property) {
|
154 | case "defineProperty":
|
155 | case "getOwnPropertyDescriptor":
|
156 | if (node.args.length < 2) break;
|
157 | exp = exp.expression;
|
158 | if (!(exp instanceof AST_SymbolRef)) break;
|
159 | if (exp.name != "Object") break;
|
160 | if (!exp.definition().undeclared) break;
|
161 | addStrings(node.args[1], add);
|
162 | break;
|
163 | case "hasOwnProperty":
|
164 | if (node.args.length < 1) break;
|
165 | addStrings(node.args[0], add);
|
166 | break;
|
167 | }
|
168 | } else if (node instanceof AST_ClassProperty) {
|
169 | if (typeof node.key == "string") add(node.key);
|
170 | } else if (node instanceof AST_Dot) {
|
171 | add(node.property);
|
172 | } else if (node instanceof AST_ObjectProperty) {
|
173 | if (typeof node.key == "string") add(node.key);
|
174 | } else if (node instanceof AST_Sub) {
|
175 | addStrings(node.property, add);
|
176 | }
|
177 | }));
|
178 |
|
179 |
|
180 | ast.walk(new TreeWalker(function(node) {
|
181 | if (node instanceof AST_Binary) {
|
182 | if (node.operator == "in") mangleStrings(node.left);
|
183 | } else if (node.TYPE == "Call") {
|
184 | var exp = node.expression;
|
185 | if (exp instanceof AST_Dot) switch (exp.property) {
|
186 | case "defineProperty":
|
187 | case "getOwnPropertyDescriptor":
|
188 | if (node.args.length < 2) break;
|
189 | exp = exp.expression;
|
190 | if (!(exp instanceof AST_SymbolRef)) break;
|
191 | if (exp.name != "Object") break;
|
192 | if (!exp.definition().undeclared) break;
|
193 | mangleStrings(node.args[1]);
|
194 | break;
|
195 | case "hasOwnProperty":
|
196 | if (node.args.length < 1) break;
|
197 | mangleStrings(node.args[0]);
|
198 | break;
|
199 | }
|
200 | } else if (node instanceof AST_ClassProperty) {
|
201 | if (typeof node.key == "string") node.key = mangle(node.key);
|
202 | } else if (node instanceof AST_Dot) {
|
203 | node.property = mangle(node.property);
|
204 | } else if (node instanceof AST_ObjectProperty) {
|
205 | if (typeof node.key == "string") node.key = mangle(node.key);
|
206 | } else if (node instanceof AST_Sub) {
|
207 | if (!options.keep_quoted) mangleStrings(node.property);
|
208 | }
|
209 | }));
|
210 |
|
211 |
|
212 |
|
213 | function can_mangle(name) {
|
214 | if (unmangleable.has(name)) return false;
|
215 | if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
216 | return true;
|
217 | }
|
218 |
|
219 | function should_mangle(name) {
|
220 | if (reserved.has(name)) return false;
|
221 | if (regex && !regex.test(name)) return false;
|
222 | return cache.has(name) || names_to_mangle.has(name);
|
223 | }
|
224 |
|
225 | function add(name) {
|
226 | if (can_mangle(name)) names_to_mangle.set(name, true);
|
227 | if (!should_mangle(name)) unmangleable.set(name, true);
|
228 | }
|
229 |
|
230 | function mangle(name) {
|
231 | if (!should_mangle(name)) return name;
|
232 | var mangled = cache.get(name);
|
233 | if (!mangled) {
|
234 | if (debug) {
|
235 |
|
236 | var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
|
237 | if (can_mangle(debug_mangled)) mangled = debug_mangled;
|
238 | }
|
239 |
|
240 | if (!mangled) do {
|
241 | mangled = base54(++cname);
|
242 | } while (!can_mangle(mangled));
|
243 | if (/^#/.test(name)) mangled = "#" + mangled;
|
244 | cache.set(name, mangled);
|
245 | }
|
246 | return mangled;
|
247 | }
|
248 |
|
249 | function mangleStrings(node) {
|
250 | if (node instanceof AST_Sequence) {
|
251 | mangleStrings(node.expressions.tail_node());
|
252 | } else if (node instanceof AST_String) {
|
253 | node.value = mangle(node.value);
|
254 | } else if (node instanceof AST_Conditional) {
|
255 | mangleStrings(node.consequent);
|
256 | mangleStrings(node.alternative);
|
257 | }
|
258 | }
|
259 | }
|