Skip to content

Commit ddb6167

Browse files
committed
Added a python minifier and a test.min.html, which uses the minified version.
1 parent 134ad68 commit ddb6167

File tree

4 files changed

+253
-24
lines changed

4 files changed

+253
-24
lines changed

jquery.json.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
'\r': '\\r',
4040
'"' : '\\"',
4141
'\\': '\\\\'
42-
}
42+
};
4343

4444
$.quoteString = function(string)
4545
// Places quotes around a string, inteligently.
@@ -58,10 +58,10 @@
5858
}
5959
c = a.charCodeAt();
6060
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
61-
}) + '"'
61+
}) + '"';
6262
}
6363
return '"' + string + '"';
64-
}
64+
};
6565

6666
$.toJSON = function(o, compact)
6767
{
@@ -103,10 +103,10 @@
103103
}
104104

105105
// It's probably an object, then.
106-
ret = [];
106+
var ret = [];
107107
for (var k in o) {
108108
var name;
109-
var type = typeof(k);
109+
type = typeof(k);
110110

111111
if (type == "number")
112112
name = '"' + k + '"';
@@ -115,7 +115,7 @@
115115
else
116116
continue; //skip non-string or number keys
117117

118-
val = $.toJSON(o[k], compact);
118+
var val = $.toJSON(o[k], compact);
119119
if (typeof(val) != "string") {
120120
// skip non-serializable values
121121
continue;
@@ -127,18 +127,18 @@
127127
ret.push(name + ": " + val);
128128
}
129129
return "{" + ret.join(", ") + "}";
130-
}
130+
};
131131

132132
$.compactJSON = function(o)
133133
{
134134
return $.toJSON(o, true);
135-
}
135+
};
136136

137137
$.evalJSON = function(src)
138138
// Evals JSON that we know to be safe.
139139
{
140140
return eval("(" + src + ")");
141-
}
141+
};
142142

143143
$.secureEvalJSON = function(src)
144144
// Evals JSON in a way that is *more* secure.
@@ -152,5 +152,5 @@
152152
return eval("(" + src + ")");
153153
else
154154
throw new SyntaxError("Error parsing JSON, source is not valid.");
155-
}
155+
};
156156
})(jQuery);

jquery.json.min.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1+
12
(function($){function toIntegersAtLease(n)
23
{return n<10?'0'+n:n;}
34
Date.prototype.toJSON=function(date)
45
{return this.getUTCFullYear()+'-'+
56
toIntegersAtLease(this.getUTCMonth())+'-'+
6-
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'}
7-
$.quoteString=function(string)
7+
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string)
88
{if(escapeable.test(string))
99
{return'"'+string.replace(escapeable,function(a)
1010
{var c=meta[a];if(typeof c==='string'){return c;}
11-
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"'}
12-
return'"'+string+'"';}
13-
$.toJSON=function(o,compact)
11+
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
12+
return'"'+string+'"';};$.toJSON=function(o,compact)
1413
{var type=typeof(o);if(type=="undefined")
1514
return"undefined";else if(type=="number"||type=="boolean")
1615
return o+"";else if(o===null)
@@ -23,19 +22,16 @@ if(compact)
2322
return"["+ret.join(",")+"]";else
2423
return"["+ret.join(", ")+"]";}
2524
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");}
26-
ret=[];for(var k in o){var name;var type=typeof(k);if(type=="number")
25+
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number")
2726
name='"'+k+'"';else if(type=="string")
2827
name=$.quoteString(k);else
29-
continue;val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
28+
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
3029
if(compact)
3130
ret.push(name+":"+val);else
3231
ret.push(name+": "+val);}
33-
return"{"+ret.join(", ")+"}";}
34-
$.compactJSON=function(o)
35-
{return $.toJSON(o,true);}
36-
$.evalJSON=function(src)
37-
{return eval("("+src+")");}
38-
$.secureEvalJSON=function(src)
32+
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o)
33+
{return $.toJSON(o,true);};$.evalJSON=function(src)
34+
{return eval("("+src+")");};$.secureEvalJSON=function(src)
3935
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
4036
return eval("("+src+")");else
41-
throw new SyntaxError("Error parsing JSON, source is not valid.");}})(jQuery);
37+
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery);

jsmin.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#!/usr/bin/python
2+
3+
# This code is original from jsmin by Douglas Crockford, it was translated to
4+
# Python by Baruch Even. The original code had the following copyright and
5+
# license.
6+
#
7+
# /* jsmin.c
8+
# 2007-05-22
9+
#
10+
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
11+
#
12+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
13+
# this software and associated documentation files (the "Software"), to deal in
14+
# the Software without restriction, including without limitation the rights to
15+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16+
# of the Software, and to permit persons to whom the Software is furnished to do
17+
# so, subject to the following conditions:
18+
#
19+
# The above copyright notice and this permission notice shall be included in all
20+
# copies or substantial portions of the Software.
21+
#
22+
# The Software shall be used for Good, not Evil.
23+
#
24+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30+
# SOFTWARE.
31+
# */
32+
33+
from StringIO import StringIO
34+
35+
def jsmin(js):
36+
ins = StringIO(js)
37+
outs = StringIO()
38+
JavascriptMinify().minify(ins, outs)
39+
str = outs.getvalue()
40+
if len(str) > 0 and str[0] == '\n':
41+
str = str[1:]
42+
return str
43+
44+
def isAlphanum(c):
45+
"""return true if the character is a letter, digit, underscore,
46+
dollar sign, or non-ASCII character.
47+
"""
48+
return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
49+
(c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
50+
51+
class UnterminatedComment(Exception):
52+
pass
53+
54+
class UnterminatedStringLiteral(Exception):
55+
pass
56+
57+
class UnterminatedRegularExpression(Exception):
58+
pass
59+
60+
class JavascriptMinify(object):
61+
62+
def _outA(self):
63+
self.outstream.write(self.theA)
64+
def _outB(self):
65+
self.outstream.write(self.theB)
66+
67+
def _get(self):
68+
"""return the next character from stdin. Watch out for lookahead. If
69+
the character is a control character, translate it to a space or
70+
linefeed.
71+
"""
72+
c = self.theLookahead
73+
self.theLookahead = None
74+
if c == None:
75+
c = self.instream.read(1)
76+
if c >= ' ' or c == '\n':
77+
return c
78+
if c == '': # EOF
79+
return '\000'
80+
if c == '\r':
81+
return '\n'
82+
return ' '
83+
84+
def _peek(self):
85+
self.theLookahead = self._get()
86+
return self.theLookahead
87+
88+
def _next(self):
89+
"""get the next character, excluding comments. peek() is used to see
90+
if a '/' is followed by a '/' or '*'.
91+
"""
92+
c = self._get()
93+
if c == '/':
94+
p = self._peek()
95+
if p == '/':
96+
c = self._get()
97+
while c > '\n':
98+
c = self._get()
99+
return c
100+
if p == '*':
101+
c = self._get()
102+
while 1:
103+
c = self._get()
104+
if c == '*':
105+
if self._peek() == '/':
106+
self._get()
107+
return ' '
108+
if c == '\000':
109+
raise UnterminatedComment()
110+
111+
return c
112+
113+
def _action(self, action):
114+
"""do something! What you do is determined by the argument:
115+
1 Output A. Copy B to A. Get the next B.
116+
2 Copy B to A. Get the next B. (Delete A).
117+
3 Get the next B. (Delete B).
118+
action treats a string as a single character. Wow!
119+
action recognizes a regular expression if it is preceded by ( or , or =.
120+
"""
121+
if action <= 1:
122+
self._outA()
123+
124+
if action <= 2:
125+
self.theA = self.theB
126+
if self.theA == "'" or self.theA == '"':
127+
while 1:
128+
self._outA()
129+
self.theA = self._get()
130+
if self.theA == self.theB:
131+
break
132+
if self.theA <= '\n':
133+
raise UnterminatedStringLiteral()
134+
if self.theA == '\\':
135+
self._outA()
136+
self.theA = self._get()
137+
138+
139+
if action <= 3:
140+
self.theB = self._next()
141+
if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
142+
self.theA == '=' or self.theA == ':' or
143+
self.theA == '[' or self.theA == '?' or
144+
self.theA == '!' or self.theA == '&' or
145+
self.theA == '|' or self.theA == ';' or
146+
self.theA == '{' or self.theA == '}' or
147+
self.theA == '\n'):
148+
self._outA()
149+
self._outB()
150+
while 1:
151+
self.theA = self._get()
152+
if self.theA == '/':
153+
break
154+
elif self.theA == '\\':
155+
self._outA()
156+
self.theA = self._get()
157+
elif self.theA <= '\n':
158+
raise UnterminatedRegularExpression()
159+
self._outA()
160+
self.theB = self._next()
161+
162+
163+
def _jsmin(self):
164+
"""Copy the input to the output, deleting the characters which are
165+
insignificant to JavaScript. Comments will be removed. Tabs will be
166+
replaced with spaces. Carriage returns will be replaced with linefeeds.
167+
Most spaces and linefeeds will be removed.
168+
"""
169+
self.theA = '\n'
170+
self._action(3)
171+
172+
while self.theA != '\000':
173+
if self.theA == ' ':
174+
if isAlphanum(self.theB):
175+
self._action(1)
176+
else:
177+
self._action(2)
178+
elif self.theA == '\n':
179+
if self.theB in ['{', '[', '(', '+', '-']:
180+
self._action(1)
181+
elif self.theB == ' ':
182+
self._action(3)
183+
else:
184+
if isAlphanum(self.theB):
185+
self._action(1)
186+
else:
187+
self._action(2)
188+
else:
189+
if self.theB == ' ':
190+
if isAlphanum(self.theA):
191+
self._action(1)
192+
else:
193+
self._action(3)
194+
elif self.theB == '\n':
195+
if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
196+
self._action(1)
197+
else:
198+
if isAlphanum(self.theA):
199+
self._action(1)
200+
else:
201+
self._action(3)
202+
else:
203+
self._action(1)
204+
205+
def minify(self, instream, outstream):
206+
self.instream = instream
207+
self.outstream = outstream
208+
self.theA = '\n'
209+
self.theB = None
210+
self.theLookahead = None
211+
212+
self._jsmin()
213+
self.instream.close()
214+
215+
if __name__ == '__main__':
216+
import sys
217+
jsm = JavascriptMinify()
218+
jsm.minify(sys.stdin, sys.stdout)

test.min.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<html>
2+
<head>
3+
<script type='text/javascript' src='http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js'></script>
4+
<script type='text/javascript' src='jquery.json.min.js'></script>
5+
<script type='text/javascript' src='jquery.json.test.js'></script>
6+
7+
<style type='text/css'>
8+
.passed { color: #88FF88; }
9+
.fail { color: #FF8888; }
10+
</style>
11+
</head>
12+
<body>
13+
<h1>Tests: <span>Invalid</span></h1>
14+
</body>
15+
</html>

0 commit comments

Comments
 (0)