front-compiler 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/front_compiler.rb +1 -1
- data/lib/front_compiler/css_source.rb +1 -0
- data/lib/front_compiler/java_script.rb +1 -1
- data/lib/front_compiler/java_script/names_compactor.rb +35 -9
- data/lib/front_compiler/source_code.rb +6 -1
- data/spec/lib/front_compiler/css_source_spec.rb +14 -6
- data/spec/lib/front_compiler/java_script/names_compactor_spec.rb +146 -2
- data/spec/lib/front_compiler/java_script_spec.rb +44 -4
- metadata +19 -6
data/lib/front_compiler.rb
CHANGED
@@ -38,7 +38,7 @@ class FrontCompiler::JavaScript < FrontCompiler::SourceCode
|
|
38
38
|
gsub!(/\s+/im, ' ') # cutting down all spaces to the minimum
|
39
39
|
gsub!(/\s*(=|\+|\-|<|>|\?|\|\||&&|\!|\{|\}|,|\)|\(|;|\]|\[|:|\*|\/)\s*/im, '\1')
|
40
40
|
gsub!(/;(\})/, '\1') # removing unnecessary semicolons
|
41
|
-
gsub!(/([^a-z\d_\$]typeof)\
|
41
|
+
gsub!(/([^a-z\d_\$]typeof)\(([^\)]+)\)\s*/im, '\1 \2') # converting the typeof calls
|
42
42
|
strip!
|
43
43
|
end
|
44
44
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# This module is a part of the JavaScript class and taken out
|
5
5
|
# just to keep the things simple
|
6
6
|
#
|
7
|
-
# Copyright (C) Nikolay
|
7
|
+
# Copyright (C) 2008-2010 Nikolay Nemshilov
|
8
8
|
#
|
9
9
|
class FrontCompiler
|
10
10
|
class JavaScript < FrontCompiler::SourceCode
|
@@ -24,6 +24,7 @@ class FrontCompiler
|
|
24
24
|
([a-z\d\\$\s_,]*) # arguments list
|
25
25
|
\)\s* # end of the function definition
|
26
26
|
}imx
|
27
|
+
|
27
28
|
def compact_names_of(src)
|
28
29
|
offset = 0
|
29
30
|
while pos = src.index(FUNCTION_START_RE, offset)
|
@@ -71,11 +72,23 @@ class FrontCompiler
|
|
71
72
|
|
72
73
|
# makes decisions about the names cutting down
|
73
74
|
def guess_names_map(body, names)
|
74
|
-
|
75
|
-
|
75
|
+
# collecting a list of short var names
|
76
|
+
@replacements ||= ('a'...'z').to_a.
|
77
|
+
concat(('A'...'Z').to_a).
|
78
|
+
concat(('aa'...'zz').to_a).
|
79
|
+
concat(('a'...'z').collect{ |c| ('A'...'Z').collect{|n| c + n}}.flatten).
|
80
|
+
concat(('A'...'Z').collect{ |c| ('a'...'z').collect{|n| c + n}}.flatten).
|
81
|
+
concat(('AA'...'ZZ').to_a)
|
76
82
|
|
77
|
-
|
83
|
+
# sorting the names by their impact on the size
|
84
|
+
names_impact = get_names_impact_map(body, names)
|
85
|
+
names.sort! do |a, b|
|
86
|
+
names_impact[b] <=> names_impact[a]
|
87
|
+
end
|
78
88
|
|
89
|
+
# finding the new variable names
|
90
|
+
names_map = { }
|
91
|
+
used_renames = []
|
79
92
|
names.each do |name|
|
80
93
|
[name[/[a-z]/i]||'a'].concat(@replacements).each do |rename|
|
81
94
|
if !used_renames.include?(rename) and !body.match(/[^\w\d_\.\$]#{rename}[^\w\d_\$]/)
|
@@ -117,19 +130,21 @@ class FrontCompiler
|
|
117
130
|
end
|
118
131
|
|
119
132
|
# getting the vars definitions
|
120
|
-
body.scan(/[\s\(:;=\{\[^$]+var\s(.*?)(
|
133
|
+
body.scan(/[\s\(:;=\{\[^$]+var\s(.*?)(;|\Z)/im) do |match|
|
121
134
|
line = $1.dup
|
122
135
|
|
123
136
|
# removing arrays and objects definitions out of the line
|
124
137
|
['[]', '{}'].each do |token|
|
125
|
-
|
126
|
-
|
138
|
+
offset = 0
|
139
|
+
while pos = line.index(token=='[]' ? /\[.*?\]/ : /\{.*?\}/, offset)
|
140
|
+
block = find_block(token, pos, line)
|
141
|
+
line[pos, block.size] = ''
|
142
|
+
|
143
|
+
offset = pos + 1
|
127
144
|
end
|
128
145
|
end
|
129
146
|
|
130
|
-
|
131
147
|
# removing objects definitions
|
132
|
-
|
133
148
|
names.concat(line.split(",").collect{ |token|
|
134
149
|
token[/[\w\d_\$]+/i]
|
135
150
|
}.compact)
|
@@ -137,6 +152,17 @@ class FrontCompiler
|
|
137
152
|
|
138
153
|
names
|
139
154
|
end
|
155
|
+
|
156
|
+
# builds the map of names size impact on the body
|
157
|
+
def get_names_impact_map(body, names)
|
158
|
+
impact_map = {}
|
159
|
+
|
160
|
+
names.each do |name|
|
161
|
+
impact_map[name] = body.scan(/[^\w\d_\.\$]#{name}[^\w\d_\$]/).size
|
162
|
+
end
|
163
|
+
|
164
|
+
impact_map
|
165
|
+
end
|
140
166
|
end
|
141
167
|
end
|
142
168
|
end
|
@@ -66,7 +66,12 @@ protected
|
|
66
66
|
|
67
67
|
# bgingin the strings back
|
68
68
|
outtakes.reverse.each do |s|
|
69
|
-
|
69
|
+
original = s[:original]
|
70
|
+
|
71
|
+
# converting quotes into
|
72
|
+
original.gsub! "'", '"' if /\A'[^'"]+'\Z/ =~ original
|
73
|
+
|
74
|
+
gsub! s[:replacement], original.gsub('\\','\\\\\\\\') # <- escapes reescaping
|
70
75
|
end
|
71
76
|
@in_string_safe_mode = false
|
72
77
|
|
@@ -32,7 +32,7 @@ describe FrontCompiler::CssSource do
|
|
32
32
|
}
|
33
33
|
|
34
34
|
a:after {
|
35
|
-
content:
|
35
|
+
content: "/* */";
|
36
36
|
}
|
37
37
|
}
|
38
38
|
end
|
@@ -81,9 +81,9 @@ describe FrontCompiler::CssSource do
|
|
81
81
|
form p label {
|
82
82
|
display: block;
|
83
83
|
}
|
84
|
-
}).remove_trailing_spaces!.should == ""\
|
85
|
-
"html,body{cusor:pointer;color:red}div>p~label:after{"\
|
86
|
-
"content
|
84
|
+
}).remove_trailing_spaces!.should == "" \
|
85
|
+
"html,body{cusor:pointer;color:red}div>p~label:after{" \
|
86
|
+
"content:\" \";text-decoration:underline}" \
|
87
87
|
"form p label{display:block}"
|
88
88
|
end
|
89
89
|
|
@@ -104,8 +104,16 @@ describe FrontCompiler::CssSource do
|
|
104
104
|
content: "something";
|
105
105
|
}
|
106
106
|
}).to_javascript.should ==
|
107
|
-
'document.write("<style type=\\"text/css\\">'
|
108
|
-
'div,p{padding:10pt;background:url(
|
107
|
+
'document.write("<style type=\\"text/css\\">' \
|
108
|
+
'div,p{padding:10pt;background:url(\\"something\\");content:\"something\"}' \
|
109
109
|
'</style>");'
|
110
110
|
end
|
111
|
+
|
112
|
+
it "should keep the no-repeat option with a space in front" do
|
113
|
+
css(%{
|
114
|
+
div {
|
115
|
+
background: url("boo.hoo") no-repeat 0 0 scroll #fff;
|
116
|
+
}
|
117
|
+
}).compact!.should == 'div{background:url("boo.hoo") no-repeat 0 0 scroll #fff}'
|
118
|
+
end
|
111
119
|
end
|
@@ -166,13 +166,13 @@ describe FrontCompiler::JavaScript::NamesCompactor do
|
|
166
166
|
}
|
167
167
|
}).should == %{
|
168
168
|
function(b) {
|
169
|
-
function
|
169
|
+
function a() {
|
170
170
|
function f() {
|
171
171
|
var m = b * 2;
|
172
172
|
b(m);
|
173
173
|
}
|
174
174
|
}
|
175
|
-
var
|
175
|
+
var c = a(b);
|
176
176
|
}
|
177
177
|
}
|
178
178
|
end
|
@@ -216,4 +216,148 @@ describe FrontCompiler::JavaScript::NamesCompactor do
|
|
216
216
|
}
|
217
217
|
}
|
218
218
|
end
|
219
|
+
|
220
|
+
it "should process the multi-lined variable definitions with complex constructions in them" do
|
221
|
+
compact(%{
|
222
|
+
function() {
|
223
|
+
var boo = [],
|
224
|
+
hoo = {
|
225
|
+
doo: [[1], [2], [3], {
|
226
|
+
moo: {
|
227
|
+
zoo: [[[[[1]]]]]
|
228
|
+
}
|
229
|
+
}]
|
230
|
+
},
|
231
|
+
foo = function() {
|
232
|
+
|
233
|
+
};
|
234
|
+
|
235
|
+
foo(boo, hoo);
|
236
|
+
}
|
237
|
+
}).should == %{
|
238
|
+
function() {
|
239
|
+
var b = [],
|
240
|
+
h = {
|
241
|
+
doo: [[1], [2], [3], {
|
242
|
+
moo: {
|
243
|
+
zoo: [[[[[1]]]]]
|
244
|
+
}
|
245
|
+
}]
|
246
|
+
},
|
247
|
+
f = function() {
|
248
|
+
|
249
|
+
};
|
250
|
+
|
251
|
+
f(b, h);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should process multilined variables with cross-calls" do
|
257
|
+
compact(%{
|
258
|
+
function() {
|
259
|
+
var boo = "boo", hoo = {
|
260
|
+
moo: boo,
|
261
|
+
doo: {
|
262
|
+
zoo: boo
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}).should == %{
|
267
|
+
function() {
|
268
|
+
var b = "boo", h = {
|
269
|
+
moo: b,
|
270
|
+
doo: {
|
271
|
+
zoo: b
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should process several variable definitions in a mixed situation" do
|
279
|
+
compact(%{
|
280
|
+
function() {
|
281
|
+
var boo = "boo", hoo = "hoo";
|
282
|
+
|
283
|
+
function () {
|
284
|
+
return boo + hoo + moo + noo();
|
285
|
+
}
|
286
|
+
|
287
|
+
var moo = "moo",
|
288
|
+
zoo = "zoo",
|
289
|
+
doo = "doo";
|
290
|
+
|
291
|
+
function noo() {
|
292
|
+
return boo + hoo + zoo;
|
293
|
+
}
|
294
|
+
|
295
|
+
return boo + hoo + zoo + doo;
|
296
|
+
}
|
297
|
+
}).should == %{
|
298
|
+
function() {
|
299
|
+
var b = "boo", h = "hoo";
|
300
|
+
|
301
|
+
function () {
|
302
|
+
return b + h + m + n();
|
303
|
+
}
|
304
|
+
|
305
|
+
var m = "moo",
|
306
|
+
z = "zoo",
|
307
|
+
d = "doo";
|
308
|
+
|
309
|
+
function n() {
|
310
|
+
return b + h + z;
|
311
|
+
}
|
312
|
+
|
313
|
+
return b + h + z + d;
|
314
|
+
}
|
315
|
+
}
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should negotiate the var names pushing the better optimizations upper" do
|
319
|
+
compact(%{
|
320
|
+
function() {
|
321
|
+
var a, b, c, d;
|
322
|
+
|
323
|
+
var aaron = 'aaron',
|
324
|
+
bobby = 'bobby',
|
325
|
+
carry = 'carry',
|
326
|
+
dicky = 'dicky';
|
327
|
+
|
328
|
+
return aaron +
|
329
|
+
bobby + bobby +
|
330
|
+
carry + carry + carry +
|
331
|
+
dicky + dicky + dicky + dicky;
|
332
|
+
}
|
333
|
+
}).should == %{
|
334
|
+
function() {
|
335
|
+
var a, b, c, d;
|
336
|
+
|
337
|
+
var h = "aaron",
|
338
|
+
g = "bobby",
|
339
|
+
f = "carry",
|
340
|
+
e = "dicky";
|
341
|
+
|
342
|
+
return h +
|
343
|
+
g + g +
|
344
|
+
f + f + f +
|
345
|
+
e + e + e + e;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should not screw with external variable in a case like that" do
|
351
|
+
compact(%{
|
352
|
+
function() {
|
353
|
+
for (var i=0, natives = [Array, Function, Number, String, Date, RegExp]; i < natives.length; i++) {
|
354
|
+
}
|
355
|
+
}
|
356
|
+
}).should == %{
|
357
|
+
function() {
|
358
|
+
for (var i=0, n = [Array, Function, Number, String, Date, RegExp]; i < n.length; i++) {
|
359
|
+
}
|
360
|
+
}
|
361
|
+
}
|
362
|
+
end
|
219
363
|
end
|
@@ -23,13 +23,13 @@ describe FrontCompiler::JavaScript do
|
|
23
23
|
js(%{
|
24
24
|
|
25
25
|
var str1 = "asdfsdf \\n\\n\\n asd";
|
26
|
-
var str2 =
|
26
|
+
var str2 = "asdfasdf";
|
27
27
|
|
28
28
|
|
29
29
|
|
30
30
|
}).remove_empty_lines!.should == %{
|
31
31
|
var str1 = "asdfsdf \\n\\n\\n asd";
|
32
|
-
var str2 =
|
32
|
+
var str2 = "asdfasdf";
|
33
33
|
}
|
34
34
|
end
|
35
35
|
|
@@ -50,11 +50,51 @@ describe FrontCompiler::JavaScript do
|
|
50
50
|
js(%{
|
51
51
|
var str = "asdf \\\\ \\n /* asdf */";
|
52
52
|
var str = /\\D/;
|
53
|
-
var str =
|
53
|
+
var str = "\\D";
|
54
54
|
}).remove_comments!.should == %{
|
55
55
|
var str = "asdf \\\\ \\n /* asdf */";
|
56
56
|
var str = /\\D/;
|
57
|
-
var str =
|
57
|
+
var str = "\\D";
|
58
58
|
}
|
59
59
|
end
|
60
|
+
|
61
|
+
it "should convert single quotes to doubles in simple cases" do
|
62
|
+
js(%{
|
63
|
+
var str = 'asdfasdfdsaf';
|
64
|
+
var str = 'asdfasdfasdfa"sdfasdf';
|
65
|
+
}).remove_comments!.should == %{
|
66
|
+
var str = "asdfasdfdsaf";
|
67
|
+
var str = 'asdfasdfasdfa"sdfasdf';
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should optimize the typeof() calls in javascript" do
|
72
|
+
js(%Q{
|
73
|
+
var t = typeof(something);
|
74
|
+
if (typeof(something) == "boo")
|
75
|
+
boo();
|
76
|
+
else if (typeof something == "hoo")
|
77
|
+
hoo();
|
78
|
+
|
79
|
+
switch (typeof(something)) {
|
80
|
+
case "boo": hoo();
|
81
|
+
}
|
82
|
+
|
83
|
+
switch (typeof something) {
|
84
|
+
case "boo": hoo();
|
85
|
+
}
|
86
|
+
|
87
|
+
return typeof(value) !== "undefined" &&
|
88
|
+
typeof(value.hasOwnProperty) !== "undefined"
|
89
|
+
}).remove_trailing_spaces!.should == "" \
|
90
|
+
'var t=typeof something;' \
|
91
|
+
'if(typeof something=="boo")' \
|
92
|
+
'boo();' \
|
93
|
+
'else if(typeof something=="hoo")' \
|
94
|
+
'hoo();' \
|
95
|
+
'switch(typeof something){case "boo":hoo()}' \
|
96
|
+
'switch(typeof something){case "boo":hoo()}' \
|
97
|
+
'return typeof value!=="undefined"&&' \
|
98
|
+
'typeof value.hasOwnProperty!=="undefined"'
|
99
|
+
end
|
60
100
|
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: front-compiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 1.1.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Nikolay Nemshilov
|
@@ -9,11 +15,11 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2010-06-20 00:00:00 +04:00
|
13
19
|
default_executable:
|
14
20
|
dependencies: []
|
15
21
|
|
16
|
-
description: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor. It provides the basic JavaScript/CSS/HTML minifying feature. Plus it can create albeit packed JavaScript files, can inline CSS inside JavaScript, works with DRYed CSS files and also can work as a RubyOnRails plugin.
|
22
|
+
description: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor. It provides the basic JavaScript/CSS/HTML minifying feature. Plus it can create albeit packed JavaScript files, can inline CSS inside of JavaScript, works with DRYed CSS files and also can work as a RubyOnRails plugin.
|
17
23
|
email: nemshilov@gmail.com
|
18
24
|
executables:
|
19
25
|
- frontcc
|
@@ -50,6 +56,7 @@ files:
|
|
50
56
|
- CHANGELOG
|
51
57
|
- Rakefile
|
52
58
|
- init.rb
|
59
|
+
- bin/frontcc
|
53
60
|
has_rdoc: true
|
54
61
|
homepage: http://github.com/MadRabbit/frontcompiler
|
55
62
|
licenses: []
|
@@ -60,21 +67,27 @@ rdoc_options: []
|
|
60
67
|
require_paths:
|
61
68
|
- lib
|
62
69
|
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
63
71
|
requirements:
|
64
72
|
- - ">="
|
65
73
|
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
66
77
|
version: "0"
|
67
|
-
version:
|
68
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
69
80
|
requirements:
|
70
81
|
- - ">="
|
71
82
|
- !ruby/object:Gem::Version
|
83
|
+
hash: 3
|
84
|
+
segments:
|
85
|
+
- 0
|
72
86
|
version: "0"
|
73
|
-
version:
|
74
87
|
requirements: []
|
75
88
|
|
76
89
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.3.
|
90
|
+
rubygems_version: 1.3.7
|
78
91
|
signing_key:
|
79
92
|
specification_version: 3
|
80
93
|
summary: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor
|