front-compiler 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|