2 Packer version 3.0 (beta 5) - copyright 2004-2007, Dean Edwards
\r
3 http://www.opensource.org/licenses/mit-license
\r
6 eval(base2.namespace);
\r
8 var IGNORE = RegGrp.IGNORE;
\r
13 var Packer = Base.extend({
\r
14 minify: function(script) {
\r
15 script = script.replace(Packer.CONTINUE, "");
\r
16 script = Packer.clean.exec(script);
\r
17 script = Packer.whitespace.exec(script);
\r
18 script = Packer.clean.exec(script); // seem to grab a few more bytes on the second pass
\r
22 pack: function(script, base62, shrink) {
\r
23 script = this.minify(script);
\r
24 if (shrink) script = this._shrinkVariables(script);
\r
25 if (base62) script = this._base62Encode(script);
\r
29 _base62Encode: function(script) {
\r
30 var words = new Words(script);
\r
31 var encode = function(word) {
\r
32 return words.fetch(word).encoded;
\r
35 /* build the packed script */
\r
37 var p = this._escape(script.replace(WORDS, encode));
\r
38 var a = Math.min(Math.max(words.count(), 2), 62);
\r
39 var c = words.count();
\r
41 var e = Packer["ENCODE" + (a > 10 ? a > 36 ? 62 : 36 : 10)];
\r
42 var r = a > 10 ? "e(c)" : "c";
\r
45 return format(Packer.UNPACK, p,a,c,k,e,r);
\r
48 _escape: function(script) {
\r
49 // single quotes wrap the final string so escape them
\r
50 // also escape new lines required by conditional comments
\r
51 return script.replace(/([\\'])/g, "\\$1").replace(/[\r\n]+/g, "\\n");
\r
54 _shrinkVariables: function(script) {
\r
55 // Windows Scripting Host cannot do regexp.test() on global regexps.
\r
56 var global = function(regexp) {
\r
57 // This function creates a global version of the passed regexp.
\r
58 return new RegExp(regexp.source, "g");
\r
61 var data = []; // encoded strings and regular expressions
\r
62 var store = function(string) {
\r
63 var replacement = "#" + data.length;
\r
68 // Base52 encoding (a-Z)
\r
69 var encode52 = function(c) {
\r
70 return (c < 52 ? '' : arguments.callee(parseInt(c / 52))) +
\r
71 ((c = c % 52) > 25 ? String.fromCharCode(c + 39) : String.fromCharCode(c + 97));
\r
74 // identify blocks, particularly identify function blocks (which define scope)
\r
75 var BLOCK = /(function\s*[\w$]*\s*\(\s*([^\)]*)\s*\)\s*)?(\{([^{}]*)\})/;
\r
76 var VAR_ = /var\s+/g;
\r
77 var VAR_NAME = /var\s+[\w$]{2,}/g; // > 1 char
\r
78 var COMMA = /\s*,\s*/;
\r
79 var blocks = []; // store program blocks (anything between braces {})
\r
80 // encoder for program blocks
\r
81 var encode = function(block, func, args) {
\r
82 if (func) { // the block is a function block
\r
84 // decode the function block (THIS IS THE IMPORTANT BIT)
\r
85 // We are retrieving all sub-blocks and will re-parse them in light
\r
86 // of newly shrunk variables
\r
87 block = decode(block);
\r
89 // create the list of variable and argument names
\r
90 var vars = match(block, VAR_NAME).join(",").replace(VAR_, "");
\r
91 var ids = Array2.combine(args.split(COMMA).concat(vars.split(COMMA)));
\r
93 // process each identifier
\r
94 var count = 0, shortId;
\r
95 forEach (ids, function(id) {
\r
96 id = rescape(trim(id));
\r
98 // find the next free short name (check everything in the current scope)
\r
99 do shortId = encode52(count++);
\r
100 while (new RegExp("[^\\w$.]" + shortId + "[^\\w$:]").test(block));
\r
101 // replace the long name with the short name
\r
102 var reg = new RegExp("([^\\w$.])" + id + "([^\\w$:])");
\r
103 while (reg.test(block)) block = block.replace(global(reg), "$1" + shortId + "$2");
\r
104 var reg = new RegExp("([^{,])" + id + ":", "g");
\r
105 block = block.replace(reg, "$1" + shortId + ":");
\r
109 var replacement = "~" + blocks.length;
\r
110 blocks.push(block);
\r
111 return replacement;
\r
114 // decoder for program blocks
\r
115 var ENCODED = /~(\d+)/;
\r
116 var decode = function(script) {
\r
117 while (ENCODED.test(script)) {
\r
118 script = script.replace(global(ENCODED), function(match, index) {
\r
119 return blocks[index];
\r
125 // encode strings and regular expressions
\r
126 script = Packer.data.exec(script, store);
\r
128 // remove closures (this is for base2 namespaces only)
\r
129 script = script.replace(/new function\(_\)\s*\{/g, "{;#;");
\r
131 // encode blocks, as we encode we replace variable and argument names
\r
132 while (BLOCK.test(script)) {
\r
133 script = script.replace(global(BLOCK), encode);
\r
136 // put the blocks back
\r
137 script = decode(script);
\r
139 // put back the closure (for base2 namespaces only)
\r
140 script = script.replace(/\{;#;/g, "new function(_){");
\r
142 // put strings and regular expressions back
\r
143 script = script.replace(/#(\d+)/g, function(match, index) {
\r
144 return data[index];
\r
150 CONTINUE: /\\\r?\n/g,
\r
152 ENCODE10: "String",
\r
153 ENCODE36: "function(c){return c.toString(a)}",
\r
154 ENCODE62: "function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))}",
\r
156 UNPACK: "eval(function(p,a,c,k,e,r){e=%5;if(!''.replace(/^/,String)){while(c--)r[%6]=k[c]" +
\r
157 "||%6;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p." +
\r
158 "replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('%1',%2,%3,'%4'.split('|'),0,{}))",
\r
161 this.data = reduce(this.data, new RegGrp, function(data, replacement, expression) {
\r
162 data.store(this.javascript.exec(expression), replacement);
\r
165 this.clean = this.data.union(this.clean);
\r
166 this.whitespace = this.data.union(this.whitespace);
\r
170 ";;;[^\\n]*": REMOVE, // triple semi-colons treated like line comments
\r
171 "\\(\\s*;\\s*;\\s*\\)": "(;;)", // for (;;) loops
\r
172 "throw[^};]+[};]": IGNORE, // a safari 1.3 bug
\r
173 ";+\\s*([};])": "$1"
\r
180 "CONDITIONAL": IGNORE, // conditional comments
\r
181 "(COMMENT1)\\n\\s*(REGEXP)?": "\n$2",
\r
182 "(COMMENT2)\\s*(REGEXP)?": " $3",
\r
183 "COMMENT1$": REMOVE,
\r
184 "([\\[(\\^=,{}:;&|!*?])\\s*(REGEXP)": "$1$2"
\r
187 javascript: new RegGrp({
\r
188 COMMENT1: /\/\/[^\n]*/.source,
\r
189 COMMENT2: /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source,
\r
190 CONDITIONAL: /\/\*@|@\*\/|\/\/@[^\n]*\n/.source,
\r
191 REGEXP: /\/(\\\/|[^*\/])(\\.|[^\/\n\\])*\//.source,
\r
192 STRING1: /'(\\.|[^'\\])*'/.source,
\r
193 STRING2: /"(\\.|[^"\\])*"/.source
\r
197 "(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])": "$1 $2", // http://dean.edwards.name/weblog/2007/04/packer3/#comment84066
\r
198 "([+-])\\s+([+-])": "$1 $2", // c = a++ +b;
\r
199 "\\b\\s+\\$\\s+\\b": " $ ", // var $ in
\r
200 "\\$\\s+\\b": "$ ", // object$ in
\r
201 "\\b\\s+\\$": " $", // return $object
\r
202 "\\b\\s+\\b": SPACE,
\r