front-compiler 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +14 -0
- data/LICENSE +20 -0
- data/README +174 -0
- data/Rakefile +82 -0
- data/bin/frontcc +53 -0
- data/init.rb +25 -0
- data/lib/front-compiler.rb +5 -0
- data/lib/front_compiler/css_source/nested_styles.rb +72 -0
- data/lib/front_compiler/css_source.rb +42 -0
- data/lib/front_compiler/html_compactor.rb +24 -0
- data/lib/front_compiler/java_script/logic_compactor.rb +135 -0
- data/lib/front_compiler/java_script/names_compactor.rb +142 -0
- data/lib/front_compiler/java_script/self_builder.rb +137 -0
- data/lib/front_compiler/java_script.rb +53 -0
- data/lib/front_compiler/source_code.rb +105 -0
- data/lib/front_compiler.rb +59 -0
- data/lib/front_compiler_helper.rb +45 -0
- data/spec/lib/front_compiler/css_source/nested_styles_spec.rb.rb +65 -0
- data/spec/lib/front_compiler/css_source_spec.rb +111 -0
- data/spec/lib/front_compiler/html_compactor_spec.rb +41 -0
- data/spec/lib/front_compiler/java_script/logic_compactor_spec.rb +363 -0
- data/spec/lib/front_compiler/java_script/names_compactor_spec.rb +219 -0
- data/spec/lib/front_compiler/java_script/self_builder_spec.rb +253 -0
- data/spec/lib/front_compiler/java_script_spec.rb +60 -0
- data/spec/lib/front_compiler/source_code_spec.rb +26 -0
- data/spec/lib/front_compiler_helper_spec.rb +34 -0
- data/spec/lib/front_compiler_spec.rb +36 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +7 -0
- metadata +82 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
* 1.0.6 (December 14, 2009) - Nikolay V. Nemshilov aka St.
|
2
|
+
* rubygem is now available
|
3
|
+
* console util was added
|
4
|
+
|
5
|
+
* 1.0.2 (April 25, 2009) - Nikolay V. Nemshilov aka St.
|
6
|
+
* Tokens negotiation process update
|
7
|
+
* The self-build script enhancement
|
8
|
+
|
9
|
+
* 1.0.0 (April 5, 2009) - Nikolay V. Nemshilov aka St.
|
10
|
+
|
11
|
+
* The Self-Build Feature was implemented
|
12
|
+
* Missed semicolons restoration feature added
|
13
|
+
* Documentation updates
|
14
|
+
* Tagged the source as version 1.0.0
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Nikolay V. Nemshilov
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
Welcome!
|
2
|
+
========
|
3
|
+
|
4
|
+
FrontCompiler is a simple collection of compactors for the JavaScript,
|
5
|
+
CSS and HTML source code. It removes trailing whitespaces, comments and
|
6
|
+
transformates the local variables to make the sourcecode shorter.
|
7
|
+
|
8
|
+
For JavaScript, it can create a more compressed self-building script
|
9
|
+
for your code, see the description below.
|
10
|
+
|
11
|
+
The library can be used as a plugin for rails. See description below.
|
12
|
+
|
13
|
+
|
14
|
+
RubyGem and Console tool
|
15
|
+
========================
|
16
|
+
|
17
|
+
FrontCompiler is now available as a rubygem at the gemcutter service
|
18
|
+
|
19
|
+
gem sources -a http://gemcutter.org
|
20
|
+
gem install front-compiler
|
21
|
+
|
22
|
+
With the rubygem you'll have a console tool called 'frontcc'
|
23
|
+
|
24
|
+
$ frontcc file0.js file1.js file2.js file3.js
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Basic Usage
|
29
|
+
===========
|
30
|
+
|
31
|
+
It's pretty simple
|
32
|
+
|
33
|
+
@c = FrontCompiler.new
|
34
|
+
|
35
|
+
@compact_js = @c.compact_js(File.open('src/something.js', 'r'));
|
36
|
+
@compact_css = @c.compact_css(File.open('src/something.css', 'r'));
|
37
|
+
@compact_html = @c.compact_html(File.open('src/something.css', 'r'));
|
38
|
+
|
39
|
+
or shorter
|
40
|
+
|
41
|
+
@compact_js = @c.compact_file('src/something.js');
|
42
|
+
@compact_css = @c.compact_file('src/something.css');
|
43
|
+
@compact_html = @c.compact_file('src/something.css');
|
44
|
+
|
45
|
+
or you can compact several files at once like that
|
46
|
+
|
47
|
+
@library_code = @c.compact_files(%w{
|
48
|
+
src/lib.js
|
49
|
+
src/lib/something.js
|
50
|
+
src/lib/another.js
|
51
|
+
})
|
52
|
+
|
53
|
+
Same for the other file-types
|
54
|
+
|
55
|
+
CSS Inlining
|
56
|
+
============
|
57
|
+
|
58
|
+
With the tool you can convert your css source in some javascript
|
59
|
+
definition so you could put the styles in the same file as your
|
60
|
+
javascript and have -1 (or several) hits to your sever.
|
61
|
+
|
62
|
+
File('public/javascripts/all_in_one.js', 'w') do |file|
|
63
|
+
file.write @c.compact_files(%w{
|
64
|
+
public/javascripts/prototype.js
|
65
|
+
public/javascripts/effects.js
|
66
|
+
public/javascripts/application.js
|
67
|
+
})
|
68
|
+
|
69
|
+
file.write @c.inline_css(
|
70
|
+
File.open('public/stylesheets/application.css').read
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
Now you have a single javascript file which contains both, javascript
|
75
|
+
and the application stylesheets in one.
|
76
|
+
|
77
|
+
NOTE: if the user have JavaScript switched off, then he won't see the
|
78
|
+
styles.
|
79
|
+
|
80
|
+
Nested CSS Handling
|
81
|
+
===================
|
82
|
+
|
83
|
+
Nested CSS is a feature when you describe your css with nested constructions
|
84
|
+
like that
|
85
|
+
|
86
|
+
div.article {
|
87
|
+
div.title {
|
88
|
+
font-weight: bold;
|
89
|
+
span.date {
|
90
|
+
color: pink;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
div.text {
|
94
|
+
background: #EEE;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
Which means the same as the following code.
|
99
|
+
|
100
|
+
div.article div.title {
|
101
|
+
font-weight: bold;
|
102
|
+
}
|
103
|
+
div.article div.title span.date {
|
104
|
+
color: pink
|
105
|
+
}
|
106
|
+
div.article div.text {
|
107
|
+
background: #EEE;
|
108
|
+
}
|
109
|
+
|
110
|
+
Nested styles are more clean, simple and follows the DRY principle. The only
|
111
|
+
little problem, there's no browsers which support the feature yet. But the idea
|
112
|
+
is alive and people like it. So we have added the feature emulation in the
|
113
|
+
project.
|
114
|
+
|
115
|
+
You can create nested css descriptions and then when you compress your css
|
116
|
+
with FrontCompiler, it will be automatically converted in a correct css source
|
117
|
+
which the browsers can understand.
|
118
|
+
|
119
|
+
|
120
|
+
Rails Usage
|
121
|
+
===========
|
122
|
+
|
123
|
+
The project can be used as a usual rails plugin. Just clone the
|
124
|
+
project into your vendor/plugins/front_compiler directory and you will
|
125
|
+
have the following methods aviable both in your controllers and
|
126
|
+
templates
|
127
|
+
|
128
|
+
|
129
|
+
* compact_files(list) - compacts the files fromt the given list and
|
130
|
+
puts them in a single string. You can specify
|
131
|
+
a list of file-names here.
|
132
|
+
|
133
|
+
* compact_file(file) - compacts the given file (can be a file-name)
|
134
|
+
|
135
|
+
* compact_js(source) - returns compacted version of the given source
|
136
|
+
* compact_css(source)
|
137
|
+
* compact_html(source)
|
138
|
+
|
139
|
+
* inline_css(source) - converts the css-source in javascript
|
140
|
+
* inline_css_file(file) - converts the given css-file in a javascript
|
141
|
+
source (can be a file-name)
|
142
|
+
|
143
|
+
|
144
|
+
Self-Build Scripts
|
145
|
+
==================
|
146
|
+
|
147
|
+
FrontCompiler provides you another nice feature, the scripts self-building.
|
148
|
+
The idea is that it will convert your code into a string, replace all long
|
149
|
+
tokens by short replacements and then compile a javascript code which will
|
150
|
+
replace all the tokens back on the user's browser side.
|
151
|
+
|
152
|
+
This will give you extra 20-40% compression over the existing FrontCompiler
|
153
|
+
compression.
|
154
|
+
|
155
|
+
The browser side restoration happens pretty quick and almost invisible for
|
156
|
+
the end user.
|
157
|
+
|
158
|
+
As the feature actually change the code and requires the end script to be
|
159
|
+
executed with JavaScript, it won't work if you use JSON as a media format
|
160
|
+
without actual evaluating it as a javascript code. For this reason, to use
|
161
|
+
the feature, you need to call it specifically.
|
162
|
+
|
163
|
+
@c = FrontCompiler.new
|
164
|
+
@c.compact_js(File.open('src/something.js', 'r')).create_self_build;
|
165
|
+
|
166
|
+
If you want FrontCompiler to create self-builds by default you can just
|
167
|
+
uncomment the call in the java_script.rb file.
|
168
|
+
|
169
|
+
|
170
|
+
Enjoy!
|
171
|
+
|
172
|
+
--
|
173
|
+
The code released under terms of the MIT License
|
174
|
+
Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St.
|
data/Rakefile
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require "rake/rdoctask"
|
5
|
+
require "rake/testtask"
|
6
|
+
require "spec/rake/spectask"
|
7
|
+
require "fileutils"
|
8
|
+
|
9
|
+
def __DIR__
|
10
|
+
File.dirname(__FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
include FileUtils
|
14
|
+
|
15
|
+
NAME = "front_compiler"
|
16
|
+
|
17
|
+
require "lib/front_compiler"
|
18
|
+
require "lib/front_compiler_helper"
|
19
|
+
|
20
|
+
def sudo
|
21
|
+
ENV['FC_SUDO'] ||= "sudo"
|
22
|
+
sudo = windows? ? "" : ENV['FC_SUDO']
|
23
|
+
end
|
24
|
+
|
25
|
+
def windows?
|
26
|
+
(PLATFORM =~ /win32|cygwin/) rescue nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def install_home
|
30
|
+
ENV['GEM_HOME'] ? "-i #{ENV['GEM_HOME']}" : ""
|
31
|
+
end
|
32
|
+
|
33
|
+
##############################################################################
|
34
|
+
# Packaging & Installation
|
35
|
+
##############################################################################
|
36
|
+
CLEAN.include ["**/.*.sw?", "pkg", "lib/*.bundle", "*.gem", "doc/rdoc", ".config", "coverage", "cache"]
|
37
|
+
|
38
|
+
desc "Run the specs."
|
39
|
+
task :default => :specs
|
40
|
+
|
41
|
+
task :frontcompiler => [:clean, :rdoc, :package]
|
42
|
+
|
43
|
+
spec = Gem::Specification.new do |s|
|
44
|
+
s.name = NAME
|
45
|
+
s.version = FrontCompiler::VERSION
|
46
|
+
s.platform = Gem::Platform::RUBY
|
47
|
+
s.author = "Nikolay V. Nemshilov"
|
48
|
+
s.email = "nemshilov@gmail.com"
|
49
|
+
s.homepage = "http://st-on-it.blogspot.com"
|
50
|
+
s.summary = "FrontCompiler is a simple collection of compactors for the JavaScript,
|
51
|
+
CSS and HTML source code. It removes trailing whitespaces, comments and
|
52
|
+
transformates the local variables to make the sourcecode shorter."
|
53
|
+
s.bindir = "bin"
|
54
|
+
s.description = s.summary
|
55
|
+
s.executables = %w( )
|
56
|
+
s.require_path = "lib"
|
57
|
+
s.files = %w( README Rakefile init.rb install.rb uninstall.rb ) + Dir["{docs,bin,spec,lib,examples,script}/**/*"]
|
58
|
+
|
59
|
+
# rdoc
|
60
|
+
s.has_rdoc = true
|
61
|
+
s.extra_rdoc_files = %w( README )
|
62
|
+
#s.rdoc_options += RDOC_OPTS + ["--exclude", "^(app|uploads)"]
|
63
|
+
|
64
|
+
# Dependencies
|
65
|
+
# s.add_dependency "something"
|
66
|
+
# Requirements
|
67
|
+
s.required_ruby_version = ">= 1.8.4"
|
68
|
+
end
|
69
|
+
|
70
|
+
Rake::GemPackageTask.new(spec) do |package|
|
71
|
+
package.gem_spec = spec
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "Run :package and install the resulting .gem"
|
75
|
+
task :install => :package do
|
76
|
+
sh %{#{sudo} gem install #{install_home} --local pkg/#{NAME}-#{FrontCompiler::VERSION}.gem --no-rdoc --no-ri}
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Run :clean and uninstall the .gem"
|
80
|
+
task :uninstall => :clean do
|
81
|
+
sh %{#{sudo} gem uninstall #{NAME}}
|
82
|
+
end
|
data/bin/frontcc
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__),'..','lib')))
|
3
|
+
|
4
|
+
require 'front_compiler'
|
5
|
+
|
6
|
+
if ARGV.empty? || ARGV.include?('-h') || ARGV.include?('--help')
|
7
|
+
puts %Q{FrontCompiler the Ruby based JavaScript/CSS/HTML compiler
|
8
|
+
(C) 2008-2009 Nikolay Nemshilov
|
9
|
+
|
10
|
+
|
11
|
+
frontcc [options] file file file ...
|
12
|
+
|
13
|
+
options:
|
14
|
+
-h Show this help
|
15
|
+
-p Create an albeit packed script
|
16
|
+
|
17
|
+
|
18
|
+
The command supports any standard console */* selectors
|
19
|
+
and will automatically recognize file-types by extensions
|
20
|
+
}
|
21
|
+
else
|
22
|
+
cc = FrontCompiler.new
|
23
|
+
|
24
|
+
javascript = false
|
25
|
+
|
26
|
+
# creating an overall source
|
27
|
+
source = ARGV.collect{ |path| Dir[path] }.flatten.collect do |path|
|
28
|
+
if File.exists? path
|
29
|
+
src = File.open(path, 'r').read
|
30
|
+
|
31
|
+
case path.split('.').last.downcase
|
32
|
+
when "html"
|
33
|
+
throw "We don't inline HTML into JavaScript" if javascript
|
34
|
+
cc.compact_html(src)
|
35
|
+
when "css"
|
36
|
+
cc.send(javascript ? :inline_css : :compact_css, src)
|
37
|
+
when "js"
|
38
|
+
javascript = true
|
39
|
+
src =~ /;\s*\Z/ ? src : (src + ';') # <- checking the end semicolon
|
40
|
+
|
41
|
+
else
|
42
|
+
throw "Unsupported kind of file '#{path}'"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end.compact.join("")
|
46
|
+
|
47
|
+
if javascript
|
48
|
+
source = cc.compact_js(source)
|
49
|
+
source = source.create_self_build if ARGV.include?('-p')
|
50
|
+
end
|
51
|
+
|
52
|
+
puts source
|
53
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'front_compiler'))
|
2
|
+
|
3
|
+
if defined? ActionController
|
4
|
+
ActionController::Base.class_eval {
|
5
|
+
include FrontCompilerHelper
|
6
|
+
helper FrontCompilerHelper
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
# Rails 2.2
|
11
|
+
if defined? ActionView::Helpers::AssetTagHelper::AssetCollection
|
12
|
+
ActionView::Helpers::AssetTagHelper::JavaScriptSources.class_eval do
|
13
|
+
alias :original_joined_contents :joined_contents
|
14
|
+
def joined_contents
|
15
|
+
FrontCompiler.new.compact_js(original_joined_contents)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
ActionView::Helpers::AssetTagHelper::StylesheetSources.class_eval do
|
19
|
+
alias :original_joined_contents :joined_contents
|
20
|
+
def joined_contents
|
21
|
+
FrontCompiler.new.compact_css(original_joined_contents)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#
|
2
|
+
# This module contains the nested css handling
|
3
|
+
# it converts virtual nested css constructions to standard css constructions
|
4
|
+
#
|
5
|
+
# Copyright (C) Nikolay V. Nemshilov aka St.
|
6
|
+
#
|
7
|
+
class FrontCompiler
|
8
|
+
class FrontCompiler::CssSource < FrontCompiler::SourceCode
|
9
|
+
module NestedStyles
|
10
|
+
# overloads the constructor, to convert the styles on fly
|
11
|
+
def initialize(src, keep_as_is=false)
|
12
|
+
super src
|
13
|
+
convert_nested_styles! unless keep_as_is
|
14
|
+
end
|
15
|
+
|
16
|
+
# converts the nested styles constructions in the source
|
17
|
+
CSS_CONSTRUCTION_RE = /((\A|\}|;)\s*?([^\}\{;]+?)\s*?)\{.*?\}/m
|
18
|
+
def convert_nested_styles!
|
19
|
+
# loop though the blocks
|
20
|
+
offset = 0
|
21
|
+
while pos = index(CSS_CONSTRUCTION_RE, offset)
|
22
|
+
pos += $1.size # <- getting the actual block position
|
23
|
+
block = find_block("{}", pos)
|
24
|
+
block = block[1, block.size-1]; pos+=1 # <- remove the container
|
25
|
+
block_size = block.size
|
26
|
+
|
27
|
+
parent_rules = clean_rules_from $3 # <- the block rules list
|
28
|
+
|
29
|
+
block_sub_styles = []
|
30
|
+
|
31
|
+
# looking for a nested construction
|
32
|
+
while block_pos = block.index(CSS_CONSTRUCTION_RE)
|
33
|
+
trail_char = $2.dup
|
34
|
+
|
35
|
+
block_start = $1.dup
|
36
|
+
block_start = block_start[trail_char.size, block_start.size]
|
37
|
+
block_start_size = block_start.size
|
38
|
+
|
39
|
+
block_pos += trail_char.size # <- updating the sub-block position
|
40
|
+
|
41
|
+
# update the sub-bolock rules
|
42
|
+
clean_rules_from($3).each do |block_rule|
|
43
|
+
block_start.gsub! block_rule, parent_rules.collect{ |p_rule|
|
44
|
+
"#{p_rule} #{block_rule}"
|
45
|
+
}.join(", ")
|
46
|
+
end
|
47
|
+
|
48
|
+
# getting the construction body
|
49
|
+
block_body = find_block("{}", block_pos + block_start_size, block)
|
50
|
+
|
51
|
+
# removing the construction out of the block
|
52
|
+
block[block_pos, block_start_size + block_body.size] = ''
|
53
|
+
block_sub_styles << block_start + block_body
|
54
|
+
end
|
55
|
+
|
56
|
+
# replacing the block
|
57
|
+
self[pos, block_size] = block + block_sub_styles.join('')
|
58
|
+
|
59
|
+
offset = pos + block.size - 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
# creates a clean css-rules list out of the str
|
65
|
+
def clean_rules_from(str)
|
66
|
+
str.split(',').collect{ |rule|
|
67
|
+
rule.gsub(/\s+/, ' ').gsub(/\/\*.*?\*\//im, '').strip
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# The CSS sources compactor
|
3
|
+
#
|
4
|
+
# Copyright (C) Nikolay V. Nemshilov aka St.
|
5
|
+
#
|
6
|
+
require "front_compiler/css_source/nested_styles"
|
7
|
+
|
8
|
+
class FrontCompiler::CssSource < FrontCompiler::SourceCode
|
9
|
+
include NestedStyles
|
10
|
+
|
11
|
+
# removes all the comments out of the given source
|
12
|
+
def remove_comments!
|
13
|
+
string_safely do
|
14
|
+
gsub!(/\/\*.*?\*\//im, '')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# removes all the empty lines out of the source code
|
19
|
+
def remove_empty_lines!
|
20
|
+
string_safely do
|
21
|
+
gsub!(/\n\s*\n/m, "\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# removes tailing whitespaces out of the source code
|
26
|
+
def remove_trailing_spaces!
|
27
|
+
string_safely do
|
28
|
+
gsub!(/\s+/im, ' ')
|
29
|
+
gsub!(/\s*(\+|>|\||~|\{|\}|,|\)|\(|;|:|\*)\s*/im, '\1')
|
30
|
+
gsub!(/;\}/, '}')
|
31
|
+
strip!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# converts the source in such a way that it could be
|
36
|
+
# delivered with javascript in the same file
|
37
|
+
def to_javascript
|
38
|
+
"document.write(\"<style type=\\\"text/css\\\">#{
|
39
|
+
compact.gsub('"', '\"')
|
40
|
+
}</style>\");"
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# The HTML sources compactor
|
3
|
+
#
|
4
|
+
# Copyright (C) Nikolay V. Nemshilov aka St.
|
5
|
+
#
|
6
|
+
class FrontCompiler::HTMLCompactor
|
7
|
+
# applies all the compactings to the given source
|
8
|
+
def minimize(source)
|
9
|
+
source = remove_comments(source)
|
10
|
+
source = remove_trailing_spaces(source)
|
11
|
+
end
|
12
|
+
|
13
|
+
# removes all the comments out of the code
|
14
|
+
def remove_comments(source)
|
15
|
+
source.gsub /<!--.*?-->/, ''
|
16
|
+
end
|
17
|
+
|
18
|
+
# remove all the trailing spaces out of the code
|
19
|
+
def remove_trailing_spaces(source)
|
20
|
+
source.gsub! /\s+/, ' '
|
21
|
+
source.gsub! />\s+/, '>'
|
22
|
+
source.gsub /\s+</, '<'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#
|
2
|
+
# This module contains the javascript logical
|
3
|
+
# structures processor/compactor
|
4
|
+
#
|
5
|
+
# This module is a part of the JavaScript class and taken out
|
6
|
+
# just to keep the things simple
|
7
|
+
#
|
8
|
+
# Copyright (C) Nikolay V. Nemshilov aka St.
|
9
|
+
#
|
10
|
+
class FrontCompiler
|
11
|
+
class JavaScript < FrontCompiler::SourceCode
|
12
|
+
module LogicCompactor
|
13
|
+
#
|
14
|
+
# checks and compacts the script-logic
|
15
|
+
#
|
16
|
+
def compact_logic!
|
17
|
+
string_safely do
|
18
|
+
join_multiline_defs!
|
19
|
+
fix_missed_semicolons!
|
20
|
+
simplify_constructions_of self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
#
|
26
|
+
# joins constructions which split on several lines
|
27
|
+
#
|
28
|
+
MULTILINING_CHARS_RE = %w{ ? : = - + * / % ! & | < > ,
|
29
|
+
}.collect{ |c| Regexp.escape(c)}.join("|")
|
30
|
+
def join_multiline_defs!
|
31
|
+
gsub!(/\s+(#{MULTILINING_CHARS_RE})\s+/m, ' \1 ')
|
32
|
+
gsub!(/\s+(#{MULTILINING_CHARS_RE})(\S)/m, ' \1\2')
|
33
|
+
gsub!(/(\S)(#{MULTILINING_CHARS_RE})\s+/m, '\1\2 ')
|
34
|
+
|
35
|
+
gsub!(/\s*(\.)\s*/m, '\1') # <- fold object member calls
|
36
|
+
|
37
|
+
gsub!(/(\()\s+/m, '\1') # <- fold method argument defs
|
38
|
+
gsub!(/\s+(\))/m, '\1')
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# tries to simplify the short logical constructions
|
43
|
+
# which were defined as multilined but could be simplier
|
44
|
+
#
|
45
|
+
def simplify_constructions_of(src)
|
46
|
+
[/(if|for|while)\s*\(/im, /(else|do)\s*\s\{/im].each do |regexp|
|
47
|
+
offset = 0
|
48
|
+
while pos = src.index(regexp, offset)
|
49
|
+
block = name = $1.dup
|
50
|
+
block += find_block("()", pos + block.size, src)
|
51
|
+
body = find_block("{}", pos + block.size, src)
|
52
|
+
|
53
|
+
unless body == ''
|
54
|
+
block += body[/\A\s*/m]; body.strip! # removing starting empty-chars
|
55
|
+
body_code = body[1, body.size-2]
|
56
|
+
|
57
|
+
# checking if the code can be simplified
|
58
|
+
can_be_simplified = number_of_code_lines_in(body_code) == 1
|
59
|
+
|
60
|
+
# check additional 'if' constructions restrictions
|
61
|
+
if can_be_simplified and name == 'if'
|
62
|
+
# double ifs construction check
|
63
|
+
can_be_simplified &= !body_code.match(/\A\s*if\s*\(/im)
|
64
|
+
|
65
|
+
# checking the else blocks missintersections
|
66
|
+
if src[pos+block.size+body.size, 40].match(/\A\s*else(\s+|\{)/)
|
67
|
+
can_be_simplified &= !body_code.match(/(\A|[^a-z\d_$])if\s*\(/)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# try to simplify internal constructions
|
72
|
+
simplify_constructions_of body_code
|
73
|
+
|
74
|
+
if can_be_simplified
|
75
|
+
check_semicolons_in body_code
|
76
|
+
else
|
77
|
+
body_code = "{#{body_code}}"
|
78
|
+
end
|
79
|
+
|
80
|
+
src[pos+block.size, body.size] = body_code
|
81
|
+
body = body_code
|
82
|
+
end
|
83
|
+
|
84
|
+
offset = pos + block.size + body.size
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# calculates the number of code-lines in the string
|
90
|
+
def number_of_code_lines_in(src)
|
91
|
+
src = src.dup
|
92
|
+
|
93
|
+
# replacing all the method calls, blocks and lists with dummies
|
94
|
+
['[]', '()', '{}'].each do |pair|
|
95
|
+
offset = 0
|
96
|
+
while pos = src.index(pair[0,1], offset)
|
97
|
+
offset = pos + 1
|
98
|
+
block = find_block(pair, 0, src[pos, src.size])
|
99
|
+
|
100
|
+
src[pos, block.size] = pair
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# putting semicolons after try/catch/finally constructions, so they were conuted as well
|
105
|
+
src.gsub!(/(catch\s*\(\)|finally)\s*\{\}/, '\&;')
|
106
|
+
src.gsub!(/\(\)\s*\{\}/, '\&;')
|
107
|
+
|
108
|
+
# calculating the number of the lines
|
109
|
+
src.split(';').collect{ |line|
|
110
|
+
line.strip != '' ? 1 : nil
|
111
|
+
}.compact.size
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# checks if there's ommited semicolons in the code
|
116
|
+
def check_semicolons_in(src)
|
117
|
+
src[/\s*\Z/m] = ";#{src[/\s*\Z/m]}" unless src.strip[-1,1].match(/[;\}]/)
|
118
|
+
|
119
|
+
# removing bug causing semicolons after a function
|
120
|
+
src.gsub!(/(\A\s*function\s*.*?\(.*?\)\s*\{.*?\});(\s*\Z)/im) do
|
121
|
+
$1 + $2
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def fix_missed_semicolons!
|
126
|
+
gsub! /([^{}()|\[&;:=,\s])([ \t]*?\n\s*?(return|if|function|while|try|do)[^a-zA-Z_$])/, '\1;\2'
|
127
|
+
|
128
|
+
# (function(){....})(..) if(...)
|
129
|
+
gsub! /(\}\)\([^)]*\))([ \t]*?\n\s*?(return|if|function|while|try|do)[^a-zA-Z_$])/, '\1;\2'
|
130
|
+
|
131
|
+
# fixing wrong added semicolons before the if calls
|
132
|
+
gsub! /([^a-zA-Z_$](else|do));(\s+(if|while|do|try)[^a-zA-Z_$])/, '\1\3'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|