csso-rails 0.0.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +4 -2
- data/README.md +12 -4
- data/Rakefile +38 -2
- data/csso-rails.gemspec +6 -8
- data/lib/csso-rails.rb +1 -6
- data/lib/csso.rb +4 -10
- data/lib/csso/rails.rb +1 -17
- data/lib/csso/version.rb +2 -2
- data/spec/csso/csso_spec.rb +15 -8
- metadata +16 -39
- data/.gitmodules +0 -3
- data/lib/csso/js/compressor.js +0 -1471
- data/lib/csso/js/csso.js +0 -70
- data/lib/csso/js/cssoapi.js +0 -22
- data/lib/csso/js/gonzales.cssp.node.js +0 -2295
- data/lib/csso/js/translator.js +0 -128
- data/lib/csso/js/util.js +0 -41
- data/lib/csso/loader.rb +0 -74
- data/lib/csso/utils.rb +0 -53
- data/spec/spec_helper.rb +0 -3
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,18 +29,26 @@ Please note than benchmark was taken in summer of 2012, since then things may ha
|
|
29
29
|
|
30
30
|
### In Rails 3.1+
|
31
31
|
add `gem 'csso-rails'` to your gemfile, and that’s it!
|
32
|
+
(also you may want to add some javascript runtime for ExecJS to pick up, like `gem 'therubyracer'`)
|
32
33
|
|
33
34
|
Upon including it becomes the default compressor even if sass is included too.
|
34
35
|
More explicit way – set in config: `config.assets.css_compressor = :csso`.
|
35
36
|
|
37
|
+
### Sprockets
|
38
|
+
|
39
|
+
If you use Sprockets without Rails:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'csso'
|
43
|
+
Csso::CssCompressor.register!
|
44
|
+
sprockets_env.css_compressor = :csso
|
45
|
+
```
|
36
46
|
|
37
47
|
### In Plain Ruby
|
38
48
|
|
39
49
|
```ruby
|
40
|
-
|
41
|
-
|
42
|
-
require 'csso'
|
43
|
-
puts Csso.optimize("a{ color: #FF0000; }") # produces "a{color:red}"
|
50
|
+
require 'csso'
|
51
|
+
puts Csso.optimize("a{ color: #FF0000; }") # produces "a{color:red}"
|
44
52
|
```
|
45
53
|
|
46
54
|
In _maniac mode_(`Csso.optimize(css, true)`, default for pipeline) CSS is processed several times until it stops getting lighter (there're cases when original csso does not do all optimizations for no reason).
|
data/Rakefile
CHANGED
@@ -1,9 +1,45 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
require 'bundler/setup'
|
3
|
-
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:spec) do |t|
|
7
|
+
t.pattern = 'spec/**/*_spec.rb'
|
8
|
+
t.libs.push 'spec'
|
9
|
+
end
|
10
|
+
|
11
|
+
$:.push File.expand_path("../lib", __FILE__)
|
12
|
+
require 'csso/version'
|
4
13
|
|
5
14
|
Bundler::GemHelper.install_tasks
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
7
15
|
|
8
16
|
task :default => :spec
|
9
17
|
|
18
|
+
|
19
|
+
file 'csso' do
|
20
|
+
puts 'Fetching csso repo...'
|
21
|
+
`git clone --single-branch --depth 1 --no-hardlinks git://github.com/css/csso`
|
22
|
+
Dir.chdir('csso'){
|
23
|
+
puts 'Now making web-version, just in case.'
|
24
|
+
`rm web/csso.web.js; make web`
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
task :update_csso => :csso do
|
29
|
+
#??
|
30
|
+
Dir.chdir('csso'){
|
31
|
+
puts 'Updating csso...'
|
32
|
+
`git pull --rebase`
|
33
|
+
`rm web/csso.web.js; make web`
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
directory 'vendor/csso'
|
38
|
+
lib_template = 'lib/csso/csso.js.erb'
|
39
|
+
file Csso::CSSO_JS_LIB => [lib_template, 'csso', 'vendor/csso', 'csso/.git/HEAD', 'csso/.git/refs/heads/master'] do
|
40
|
+
`erb #{lib_template} > #{Csso::CSSO_JS_LIB}`
|
41
|
+
end
|
42
|
+
|
43
|
+
task :generate_files => [Csso::CSSO_JS_LIB]
|
44
|
+
|
45
|
+
task :build => :generate_files
|
data/csso-rails.gemspec
CHANGED
@@ -15,17 +15,15 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.rubyforge_project = "csso-rails"
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
|
-
|
19
|
-
|
20
|
-
s.files += `git ls-files`.split("\n").map {|f| File.join(js_root,f)}
|
21
|
-
end
|
18
|
+
s.files += [Csso::CSSO_JS_LIB]
|
19
|
+
|
22
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
22
|
s.require_paths = ["lib"]
|
25
23
|
|
26
|
-
|
27
|
-
s.add_dependency
|
24
|
+
#TODO: loosen execjs dependency?
|
25
|
+
s.add_dependency 'execjs', '~>1.4'
|
28
26
|
|
29
|
-
s.add_development_dependency
|
30
|
-
s.add_development_dependency
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
s.add_development_dependency 'minitest'
|
31
29
|
end
|
data/lib/csso-rails.rb
CHANGED
data/lib/csso.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
require 'v8'
|
2
1
|
require 'csso/version'
|
3
|
-
require 'csso/
|
4
|
-
require 'csso/
|
2
|
+
require 'csso/js_lib'
|
3
|
+
require 'csso/compressor'
|
5
4
|
|
6
5
|
module Csso
|
7
6
|
|
8
|
-
@
|
9
|
-
@csso = @loader.require('cssoapi')
|
7
|
+
@csso = Csso::JsLib.new
|
10
8
|
|
11
9
|
def self.js_api
|
12
10
|
@csso
|
@@ -28,14 +26,10 @@ module Csso
|
|
28
26
|
|
29
27
|
|
30
28
|
class Optimizer
|
31
|
-
include CallJS
|
32
|
-
|
33
29
|
def optimize(css, structural_optimization=true)
|
34
30
|
return nil unless css.is_a?(String)
|
35
31
|
return css if css.size <= 3
|
36
|
-
|
37
|
-
Csso.js_api['justDoIt'].call(css, !structural_optimization)
|
38
|
-
end
|
32
|
+
Csso.js_api.compress(css, structural_optimization)
|
39
33
|
end
|
40
34
|
end
|
41
35
|
|
data/lib/csso/rails.rb
CHANGED
@@ -6,7 +6,7 @@ module Csso
|
|
6
6
|
|
7
7
|
class Railtie < ::Rails::Railtie
|
8
8
|
initializer "csso.environment", :after => "sprockets.environment" do
|
9
|
-
CssCompressor.register
|
9
|
+
CssCompressor.register!
|
10
10
|
end
|
11
11
|
|
12
12
|
# saas-rails-3.2.4(and may be others) sets itself as default, ignoring config? => override :(
|
@@ -18,20 +18,4 @@ module Csso
|
|
18
18
|
|
19
19
|
end
|
20
20
|
|
21
|
-
class CssCompressor
|
22
|
-
def compress(css)
|
23
|
-
require 'csso'
|
24
|
-
#TODO: settings?
|
25
|
-
Csso.optimize(css, true)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.register
|
29
|
-
if Sprockets.respond_to? :register_compressor
|
30
|
-
Sprockets.register_compressor('text/css', COMPRESSOR_SYM, 'Csso::CssCompressor')
|
31
|
-
else
|
32
|
-
Sprockets::Compressors.register_css_compressor(COMPRESSOR_SYM, 'Csso::CssCompressor', :default => true)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
21
|
end
|
data/lib/csso/version.rb
CHANGED
data/spec/csso/csso_spec.rb
CHANGED
@@ -1,28 +1,35 @@
|
|
1
|
-
require '
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'csso'
|
2
3
|
|
3
4
|
describe Csso do
|
4
5
|
|
6
|
+
subject { Csso }
|
7
|
+
|
8
|
+
it "dummy test" do
|
9
|
+
1.must_equal 1
|
10
|
+
end
|
11
|
+
|
5
12
|
it "should optimize css" do
|
6
|
-
subject.optimize("a {\ncolor: white; }").
|
13
|
+
subject.optimize("a {\ncolor: white; }").must_equal "a{color:#fff}"
|
7
14
|
end
|
8
15
|
|
9
16
|
it "should optimize structure" do
|
10
|
-
subject.optimize("a {\ncolor: white; } a{color: red;}").
|
17
|
+
subject.optimize("a {\ncolor: white; } a{color: red;}").must_equal "a{color:red}"
|
11
18
|
end
|
12
19
|
|
13
20
|
it "should optimize structure" do
|
14
|
-
|
21
|
+
skip "original csso is a bit broken at the moment"
|
15
22
|
# FIXME: csso produces "a{color:#fff;color:red}" on this :(
|
16
|
-
subject.optimize("a {\ncolor: white; } a{color: #ff0000;}").
|
23
|
+
subject.optimize("a {\ncolor: white; } a{color: #ff0000;}").must_equal "a{color:red}"
|
17
24
|
end
|
18
25
|
|
19
26
|
it "should optimize structure in maniac mode" do
|
20
|
-
subject.optimize("a {\ncolor: white; } a{color: #ff0000;}", true).
|
27
|
+
subject.optimize("a {\ncolor: white; } a{color: #ff0000;}", true).must_equal "a{color:red}"
|
21
28
|
end
|
22
29
|
|
23
30
|
it 'should produce no error on empty input' do
|
24
|
-
subject.optimize(nil).
|
25
|
-
subject.optimize("").
|
31
|
+
subject.optimize(nil).must_be_nil
|
32
|
+
subject.optimize("").must_equal ""
|
26
33
|
end
|
27
34
|
|
28
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csso-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,32 +9,16 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 0.10.2
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.10.2
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: commonjs
|
15
|
+
name: execjs
|
32
16
|
requirement: !ruby/object:Gem::Requirement
|
33
17
|
none: false
|
34
18
|
requirements:
|
35
19
|
- - ~>
|
36
20
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
21
|
+
version: '1.4'
|
38
22
|
type: :runtime
|
39
23
|
prerelease: false
|
40
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +26,7 @@ dependencies:
|
|
42
26
|
requirements:
|
43
27
|
- - ~>
|
44
28
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
29
|
+
version: '1.4'
|
46
30
|
- !ruby/object:Gem::Dependency
|
47
31
|
name: rake
|
48
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,21 +44,21 @@ dependencies:
|
|
60
44
|
- !ruby/object:Gem::Version
|
61
45
|
version: '0'
|
62
46
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
47
|
+
name: minitest
|
64
48
|
requirement: !ruby/object:Gem::Requirement
|
65
49
|
none: false
|
66
50
|
requirements:
|
67
|
-
- -
|
51
|
+
- - ! '>='
|
68
52
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
53
|
+
version: '0'
|
70
54
|
type: :development
|
71
55
|
prerelease: false
|
72
56
|
version_requirements: !ruby/object:Gem::Requirement
|
73
57
|
none: false
|
74
58
|
requirements:
|
75
|
-
- -
|
59
|
+
- - ! '>='
|
76
60
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
61
|
+
version: '0'
|
78
62
|
description: Invoke the CSSO from Ruby
|
79
63
|
email:
|
80
64
|
- vasilyfedoseyev@gmail.com
|
@@ -84,7 +68,6 @@ extensions: []
|
|
84
68
|
extra_rdoc_files: []
|
85
69
|
files:
|
86
70
|
- .gitignore
|
87
|
-
- .gitmodules
|
88
71
|
- .rspec
|
89
72
|
- Gemfile
|
90
73
|
- README.md
|
@@ -93,18 +76,13 @@ files:
|
|
93
76
|
- csso-rails.gemspec
|
94
77
|
- lib/csso-rails.rb
|
95
78
|
- lib/csso.rb
|
96
|
-
- lib/csso/
|
97
|
-
- lib/csso/
|
98
|
-
- lib/csso/
|
99
|
-
- lib/csso/js/gonzales.cssp.node.js
|
100
|
-
- lib/csso/js/translator.js
|
101
|
-
- lib/csso/js/util.js
|
102
|
-
- lib/csso/loader.rb
|
79
|
+
- lib/csso/compressor.rb
|
80
|
+
- lib/csso/csso.js.erb
|
81
|
+
- lib/csso/js_lib.rb
|
103
82
|
- lib/csso/rails.rb
|
104
|
-
- lib/csso/utils.rb
|
105
83
|
- lib/csso/version.rb
|
106
84
|
- spec/csso/csso_spec.rb
|
107
|
-
-
|
85
|
+
- vendor/csso/csso.js
|
108
86
|
homepage: https://github.com/Vasfed/csso-rails
|
109
87
|
licenses: []
|
110
88
|
post_install_message:
|
@@ -119,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
97
|
version: '0'
|
120
98
|
segments:
|
121
99
|
- 0
|
122
|
-
hash: -
|
100
|
+
hash: -1786311212568268028
|
123
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
102
|
none: false
|
125
103
|
requirements:
|
@@ -128,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
106
|
version: '0'
|
129
107
|
segments:
|
130
108
|
- 0
|
131
|
-
hash: -
|
109
|
+
hash: -1786311212568268028
|
132
110
|
requirements: []
|
133
111
|
rubyforge_project: csso-rails
|
134
112
|
rubygems_version: 1.8.24
|
@@ -137,4 +115,3 @@ specification_version: 3
|
|
137
115
|
summary: CSS Stylesheet optimizer/compressor for Rails
|
138
116
|
test_files:
|
139
117
|
- spec/csso/csso_spec.rb
|
140
|
-
- spec/spec_helper.rb
|
data/.gitmodules
DELETED
data/lib/csso/js/compressor.js
DELETED
@@ -1,1471 +0,0 @@
|
|
1
|
-
function TRBL(name, imp) {
|
2
|
-
this.name = TRBL.extractMain(name);
|
3
|
-
this.sides = {
|
4
|
-
'top': null,
|
5
|
-
'right': null,
|
6
|
-
'bottom': null,
|
7
|
-
'left': null
|
8
|
-
};
|
9
|
-
this.imp = imp ? 4 : 0;
|
10
|
-
}
|
11
|
-
|
12
|
-
TRBL.props = {
|
13
|
-
'margin': 1,
|
14
|
-
'margin-top': 1,
|
15
|
-
'margin-right': 1,
|
16
|
-
'margin-bottom': 1,
|
17
|
-
'margin-left': 1,
|
18
|
-
'padding': 1,
|
19
|
-
'padding-top': 1,
|
20
|
-
'padding-right': 1,
|
21
|
-
'padding-bottom': 1,
|
22
|
-
'padding-left': 1
|
23
|
-
};
|
24
|
-
|
25
|
-
TRBL.extractMain = function(name) {
|
26
|
-
var i = name.indexOf('-');
|
27
|
-
return i === -1 ? name : name.substr(0, i);
|
28
|
-
};
|
29
|
-
|
30
|
-
TRBL.prototype.impSum = function() {
|
31
|
-
var imp = 0, n = 0;
|
32
|
-
for (var k in this.sides) {
|
33
|
-
if (this.sides[k]) {
|
34
|
-
n++;
|
35
|
-
if (this.sides[k].imp) imp++;
|
36
|
-
}
|
37
|
-
}
|
38
|
-
return imp === n ? imp : 0;
|
39
|
-
};
|
40
|
-
|
41
|
-
TRBL.prototype.add = function(name, sValue, tValue, imp) {
|
42
|
-
var s = this.sides,
|
43
|
-
currentSide,
|
44
|
-
i, x, side, a = [], last,
|
45
|
-
imp = imp ? 1 : 0,
|
46
|
-
wasUnary = false;
|
47
|
-
if ((i = name.lastIndexOf('-')) !== -1) {
|
48
|
-
side = name.substr(i + 1);
|
49
|
-
if (side in s) {
|
50
|
-
if (!(currentSide = s[side]) || (imp && !currentSide.imp)) {
|
51
|
-
s[side] = { s: imp ? sValue.substring(0, sValue.length - 10) : sValue, t: [tValue[0]], imp: imp };
|
52
|
-
if (tValue[0][1] === 'unary') s[side].t.push(tValue[1]);
|
53
|
-
}
|
54
|
-
return true;
|
55
|
-
}
|
56
|
-
} else if (name === this.name) {
|
57
|
-
for (i = 0; i < tValue.length; i++) {
|
58
|
-
x = tValue[i];
|
59
|
-
last = a[a.length - 1];
|
60
|
-
switch(x[1]) {
|
61
|
-
case 'unary':
|
62
|
-
a.push({ s: x[2], t: [x], imp: imp });
|
63
|
-
wasUnary = true;
|
64
|
-
break;
|
65
|
-
case 'number':
|
66
|
-
case 'ident':
|
67
|
-
if (wasUnary) {
|
68
|
-
last.t.push(x);
|
69
|
-
last.s += x[2];
|
70
|
-
} else {
|
71
|
-
a.push({ s: x[2], t: [x], imp: imp });
|
72
|
-
}
|
73
|
-
wasUnary = false;
|
74
|
-
break;
|
75
|
-
case 'percentage':
|
76
|
-
if (wasUnary) {
|
77
|
-
last.t.push(x);
|
78
|
-
last.s += x[2][2] + '%';
|
79
|
-
} else {
|
80
|
-
a.push({ s: x[2][2] + '%', t: [x], imp: imp });
|
81
|
-
}
|
82
|
-
wasUnary = false;
|
83
|
-
break;
|
84
|
-
case 'dimension':
|
85
|
-
if (wasUnary) {
|
86
|
-
last.t.push(x);
|
87
|
-
last.s += x[2][2] + x[3][2];
|
88
|
-
} else {
|
89
|
-
a.push({ s: x[2][2] + x[3][2], t: [x], imp: imp });
|
90
|
-
}
|
91
|
-
wasUnary = false;
|
92
|
-
break;
|
93
|
-
case 's':
|
94
|
-
case 'comment':
|
95
|
-
case 'important':
|
96
|
-
break;
|
97
|
-
default:
|
98
|
-
return false;
|
99
|
-
}
|
100
|
-
}
|
101
|
-
|
102
|
-
if (a.length > 4) return false;
|
103
|
-
|
104
|
-
if (!a[1]) a[1] = a[0];
|
105
|
-
if (!a[2]) a[2] = a[0];
|
106
|
-
if (!a[3]) a[3] = a[1];
|
107
|
-
|
108
|
-
if (!s.top) s.top = a[0];
|
109
|
-
if (!s.right) s.right = a[1];
|
110
|
-
if (!s.bottom) s.bottom = a[2];
|
111
|
-
if (!s.left) s.left = a[3];
|
112
|
-
|
113
|
-
return true;
|
114
|
-
}
|
115
|
-
};
|
116
|
-
|
117
|
-
TRBL.prototype.isOkToMinimize = function() {
|
118
|
-
var s = this.sides,
|
119
|
-
imp;
|
120
|
-
|
121
|
-
if (!!(s.top && s.right && s.bottom && s.left)) {
|
122
|
-
imp = s.top.imp + s.right.imp + s.bottom.imp + s.left.imp;
|
123
|
-
return (imp === 0 || imp === 4 || imp === this.imp);
|
124
|
-
}
|
125
|
-
return false;
|
126
|
-
};
|
127
|
-
|
128
|
-
TRBL.prototype.getValue = function() {
|
129
|
-
var s = this.sides,
|
130
|
-
a = [s.top, s.right, s.bottom, s.left],
|
131
|
-
r = [{}, 'value'];
|
132
|
-
|
133
|
-
if (s.left.s === s.right.s) {
|
134
|
-
a.length--;
|
135
|
-
if (s.bottom.s === s.top.s) {
|
136
|
-
a.length--;
|
137
|
-
if (s.right.s === s.top.s) {
|
138
|
-
a.length--;
|
139
|
-
}
|
140
|
-
}
|
141
|
-
}
|
142
|
-
|
143
|
-
for (var i = 0; i < a.length - 1; i++) {
|
144
|
-
r = r.concat(a[i].t);
|
145
|
-
r.push([{ s: ' ' }, 's', ' ']);
|
146
|
-
}
|
147
|
-
r = r.concat(a[i].t);
|
148
|
-
|
149
|
-
if (this.impSum()) r.push([{ s: '!important'}, 'important']);
|
150
|
-
|
151
|
-
return r;
|
152
|
-
};
|
153
|
-
|
154
|
-
TRBL.prototype.getProperty = function() {
|
155
|
-
return [{ s: this.name }, 'property', [{ s: this.name }, 'ident', this.name]];
|
156
|
-
};
|
157
|
-
|
158
|
-
TRBL.prototype.getString = function() {
|
159
|
-
var p = this.getProperty(),
|
160
|
-
v = this.getValue().slice(2),
|
161
|
-
r = p[0].s + ':';
|
162
|
-
|
163
|
-
for (var i = 0; i < v.length; i++) r += v[i][0].s;
|
164
|
-
|
165
|
-
return r;
|
166
|
-
};
|
167
|
-
|
168
|
-
function CSSOCompressor() {}
|
169
|
-
|
170
|
-
CSSOCompressor.prototype.init = function() {
|
171
|
-
this.props = {};
|
172
|
-
this.shorts = {};
|
173
|
-
this.shorts2 = {};
|
174
|
-
|
175
|
-
this.ccrules = {}; // clean comment rules — special case to resolve ambiguity
|
176
|
-
this.crules = {}; // compress rules
|
177
|
-
this.prules = {}; // prepare rules
|
178
|
-
this.frrules = {}; // freeze ruleset rules
|
179
|
-
this.msrules = {}; // mark shorthands rules
|
180
|
-
this.csrules = {}; // clean shorthands rules
|
181
|
-
this.rbrules = {}; // restructure block rules
|
182
|
-
this.rjrules = {}; // rejoin ruleset rules
|
183
|
-
this.rrrules = {}; // restructure ruleset rules
|
184
|
-
this.frules = {}; // finalize rules
|
185
|
-
|
186
|
-
this.initRules(this.crules, this.defCCfg);
|
187
|
-
this.initRules(this.ccrules, this.cleanCfg);
|
188
|
-
this.initRules(this.frrules, this.frCfg);
|
189
|
-
this.initRules(this.prules, this.preCfg);
|
190
|
-
this.initRules(this.msrules, this.msCfg);
|
191
|
-
this.initRules(this.csrules, this.csCfg);
|
192
|
-
this.initRules(this.rbrules, this.defRBCfg);
|
193
|
-
this.initRules(this.rjrules, this.defRJCfg);
|
194
|
-
this.initRules(this.rrrules, this.defRRCfg);
|
195
|
-
this.initRules(this.frules, this.defFCfg);
|
196
|
-
|
197
|
-
this.shortGroupID = 0;
|
198
|
-
this.lastShortGroupID = 0;
|
199
|
-
this.lastShortSelector = 0;
|
200
|
-
};
|
201
|
-
|
202
|
-
CSSOCompressor.prototype.initRules = function(r, cfg) {
|
203
|
-
var o = this.order,
|
204
|
-
p = this.profile,
|
205
|
-
x, i, k,
|
206
|
-
t = [];
|
207
|
-
|
208
|
-
for (i = 0; i < o.length; i++) if (o[i] in cfg) t.push(o[i]);
|
209
|
-
|
210
|
-
if (!t.length) t = o;
|
211
|
-
for (i = 0; i < t.length; i++) {
|
212
|
-
x = p[t[i]];
|
213
|
-
for (k in x) r[k] ? r[k].push(t[i]) : r[k] = [t[i]];
|
214
|
-
}
|
215
|
-
};
|
216
|
-
|
217
|
-
CSSOCompressor.prototype.cleanCfg = {
|
218
|
-
'cleanComment': 1
|
219
|
-
};
|
220
|
-
|
221
|
-
CSSOCompressor.prototype.defCCfg = {
|
222
|
-
'cleanCharset': 1,
|
223
|
-
'cleanImport': 1,
|
224
|
-
'cleanWhitespace': 1,
|
225
|
-
'cleanDecldelim': 1,
|
226
|
-
'compressNumber': 1,
|
227
|
-
'cleanUnary': 1,
|
228
|
-
'compressColor': 1,
|
229
|
-
'compressDimension': 1,
|
230
|
-
'compressString': 1,
|
231
|
-
'compressFontWeight': 1,
|
232
|
-
'compressFont': 1,
|
233
|
-
'compressBackground': 1,
|
234
|
-
'cleanEmpty': 1
|
235
|
-
};
|
236
|
-
|
237
|
-
CSSOCompressor.prototype.defRBCfg = {
|
238
|
-
'restructureBlock': 1
|
239
|
-
};
|
240
|
-
|
241
|
-
CSSOCompressor.prototype.defRJCfg = {
|
242
|
-
'rejoinRuleset': 1,
|
243
|
-
'cleanEmpty': 1
|
244
|
-
};
|
245
|
-
|
246
|
-
CSSOCompressor.prototype.defRRCfg = {
|
247
|
-
'restructureRuleset': 1,
|
248
|
-
'cleanEmpty': 1
|
249
|
-
};
|
250
|
-
|
251
|
-
CSSOCompressor.prototype.defFCfg = {
|
252
|
-
'cleanEmpty': 1,
|
253
|
-
'delimSelectors': 1,
|
254
|
-
'delimBlocks': 1
|
255
|
-
};
|
256
|
-
|
257
|
-
CSSOCompressor.prototype.preCfg = {
|
258
|
-
'destroyDelims': 1,
|
259
|
-
'preTranslate': 1
|
260
|
-
};
|
261
|
-
|
262
|
-
CSSOCompressor.prototype.msCfg = {
|
263
|
-
'markShorthands': 1
|
264
|
-
};
|
265
|
-
|
266
|
-
CSSOCompressor.prototype.frCfg = {
|
267
|
-
'freezeRulesets': 1
|
268
|
-
};
|
269
|
-
|
270
|
-
CSSOCompressor.prototype.csCfg = {
|
271
|
-
'cleanShorthands': 1,
|
272
|
-
'cleanEmpty': 1
|
273
|
-
};
|
274
|
-
|
275
|
-
CSSOCompressor.prototype.order = [
|
276
|
-
'cleanCharset',
|
277
|
-
'cleanImport',
|
278
|
-
'cleanComment',
|
279
|
-
'cleanWhitespace',
|
280
|
-
'compressNumber',
|
281
|
-
'cleanUnary',
|
282
|
-
'compressColor',
|
283
|
-
'compressDimension',
|
284
|
-
'compressString',
|
285
|
-
'compressFontWeight',
|
286
|
-
'compressFont',
|
287
|
-
'compressBackground',
|
288
|
-
'freezeRulesets',
|
289
|
-
'destroyDelims',
|
290
|
-
'preTranslate',
|
291
|
-
'markShorthands',
|
292
|
-
'cleanShorthands',
|
293
|
-
'restructureBlock',
|
294
|
-
'rejoinRuleset',
|
295
|
-
'restructureRuleset',
|
296
|
-
'cleanEmpty',
|
297
|
-
'delimSelectors',
|
298
|
-
'delimBlocks'
|
299
|
-
];
|
300
|
-
|
301
|
-
CSSOCompressor.prototype.profile = {
|
302
|
-
'cleanCharset': {
|
303
|
-
'atrules': 1
|
304
|
-
},
|
305
|
-
'cleanImport': {
|
306
|
-
'atrules': 1
|
307
|
-
},
|
308
|
-
'cleanWhitespace': {
|
309
|
-
's': 1
|
310
|
-
},
|
311
|
-
'compressNumber': {
|
312
|
-
'number': 1
|
313
|
-
},
|
314
|
-
'cleanUnary': {
|
315
|
-
'unary': 1
|
316
|
-
},
|
317
|
-
'compressColor': {
|
318
|
-
'vhash': 1,
|
319
|
-
'funktion': 1,
|
320
|
-
'ident': 1
|
321
|
-
},
|
322
|
-
'compressDimension': {
|
323
|
-
'dimension': 1
|
324
|
-
},
|
325
|
-
'compressString': {
|
326
|
-
'string': 1
|
327
|
-
},
|
328
|
-
'compressFontWeight': {
|
329
|
-
'declaration': 1
|
330
|
-
},
|
331
|
-
'compressFont': {
|
332
|
-
'declaration': 1
|
333
|
-
},
|
334
|
-
'compressBackground': {
|
335
|
-
'declaration': 1
|
336
|
-
},
|
337
|
-
'cleanComment': {
|
338
|
-
'comment': 1
|
339
|
-
},
|
340
|
-
'cleanDecldelim': {
|
341
|
-
'block': 1
|
342
|
-
},
|
343
|
-
'cleanEmpty': {
|
344
|
-
'ruleset': 1,
|
345
|
-
'atruleb': 1,
|
346
|
-
'atruler': 1
|
347
|
-
},
|
348
|
-
'destroyDelims': {
|
349
|
-
'decldelim': 1,
|
350
|
-
'delim': 1
|
351
|
-
},
|
352
|
-
'preTranslate': {
|
353
|
-
'declaration': 1,
|
354
|
-
'property': 1,
|
355
|
-
'simpleselector': 1,
|
356
|
-
'filter': 1,
|
357
|
-
'value': 1,
|
358
|
-
'number': 1,
|
359
|
-
'percentage': 1,
|
360
|
-
'dimension': 1,
|
361
|
-
'ident': 1
|
362
|
-
},
|
363
|
-
'restructureBlock': {
|
364
|
-
'block': 1
|
365
|
-
},
|
366
|
-
'rejoinRuleset': {
|
367
|
-
'ruleset': 1
|
368
|
-
},
|
369
|
-
'restructureRuleset': {
|
370
|
-
'ruleset': 1
|
371
|
-
},
|
372
|
-
'delimSelectors': {
|
373
|
-
'selector': 1
|
374
|
-
},
|
375
|
-
'delimBlocks': {
|
376
|
-
'block': 1
|
377
|
-
},
|
378
|
-
'markShorthands': {
|
379
|
-
'block': 1
|
380
|
-
},
|
381
|
-
'cleanShorthands': {
|
382
|
-
'declaration': 1
|
383
|
-
},
|
384
|
-
'freezeRulesets': {
|
385
|
-
'ruleset': 1
|
386
|
-
}
|
387
|
-
};
|
388
|
-
|
389
|
-
CSSOCompressor.prototype.isContainer = function(o) {
|
390
|
-
if (Array.isArray(o)) {
|
391
|
-
for (var i = 0; i < o.length; i++) if (Array.isArray(o[i])) return true;
|
392
|
-
}
|
393
|
-
};
|
394
|
-
|
395
|
-
CSSOCompressor.prototype.process = function(rules, token, container, i, path) {
|
396
|
-
var rule = token[1];
|
397
|
-
if (rule && rules[rule]) {
|
398
|
-
var r = rules[rule],
|
399
|
-
x1 = token, x2,
|
400
|
-
o = this.order, k;
|
401
|
-
for (var k = 0; k < r.length; k++) {
|
402
|
-
x2 = this[r[k]](x1, rule, container, i, path);
|
403
|
-
if (x2 === null) return null;
|
404
|
-
else if (x2 !== undefined) x1 = x2;
|
405
|
-
}
|
406
|
-
}
|
407
|
-
return x1;
|
408
|
-
};
|
409
|
-
|
410
|
-
CSSOCompressor.prototype.compress = function(tree, ro) {
|
411
|
-
tree = tree || ['stylesheet'];
|
412
|
-
this.init();
|
413
|
-
this.info = true;
|
414
|
-
|
415
|
-
var x = (typeof tree[0] !== 'string') ? tree : this.injectInfo([tree])[0],
|
416
|
-
l0, l1 = 100000000000, ls,
|
417
|
-
x0, x1, xs,
|
418
|
-
protectedComment = this.findProtectedComment(tree);
|
419
|
-
|
420
|
-
// compression without restructure
|
421
|
-
x = this.walk(this.ccrules, x, '/0');
|
422
|
-
x = this.walk(this.crules, x, '/0');
|
423
|
-
x = this.walk(this.prules, x, '/0');
|
424
|
-
x = this.walk(this.frrules, x, '/0');
|
425
|
-
|
426
|
-
ls = translator.translate(cleanInfo(x)).length;
|
427
|
-
|
428
|
-
if (!ro) { // restructure ON
|
429
|
-
xs = this.copyArray(x);
|
430
|
-
x = this.walk(this.rjrules, x, '/0');
|
431
|
-
this.disjoin(x);
|
432
|
-
x = this.walk(this.msrules, x, '/0');
|
433
|
-
x = this.walk(this.csrules, x, '/0');
|
434
|
-
x = this.walk(this.rbrules, x, '/0');
|
435
|
-
do {
|
436
|
-
l0 = l1;
|
437
|
-
x0 = this.copyArray(x);
|
438
|
-
x = this.walk(this.rjrules, x, '/0');
|
439
|
-
x = this.walk(this.rrrules, x, '/0');
|
440
|
-
l1 = translator.translate(cleanInfo(x)).length;
|
441
|
-
x1 = this.copyArray(x);
|
442
|
-
} while (l0 > l1);
|
443
|
-
if (ls < l0 && ls < l1) x = xs;
|
444
|
-
else if (l0 < l1) x = x0;
|
445
|
-
}
|
446
|
-
|
447
|
-
x = this.walk(this.frules, x, '/0');
|
448
|
-
|
449
|
-
if (protectedComment) x.splice(2, 0, protectedComment);
|
450
|
-
|
451
|
-
return x;
|
452
|
-
};
|
453
|
-
|
454
|
-
CSSOCompressor.prototype.findProtectedComment = function(tree) {
|
455
|
-
var token;
|
456
|
-
for (var i = 2; i < tree.length; i++) {
|
457
|
-
token = tree[i];
|
458
|
-
if (token[1] === 'comment' && token[2].length > 0 && token[2].charAt(0) === '!') return token;
|
459
|
-
if (token[1] !== 's') return;
|
460
|
-
}
|
461
|
-
};
|
462
|
-
|
463
|
-
CSSOCompressor.prototype.injectInfo = function(token) {
|
464
|
-
var t;
|
465
|
-
for (var i = token.length - 1; i > -1; i--) {
|
466
|
-
t = token[i];
|
467
|
-
if (t && Array.isArray(t)) {
|
468
|
-
if (this.isContainer(t)) t = this.injectInfo(t);
|
469
|
-
t.splice(0, 0, {});
|
470
|
-
}
|
471
|
-
}
|
472
|
-
return token;
|
473
|
-
};
|
474
|
-
|
475
|
-
CSSOCompressor.prototype.disjoin = function(container) {
|
476
|
-
var t, s, r, sr;
|
477
|
-
|
478
|
-
for (var i = container.length - 1; i > -1; i--) {
|
479
|
-
t = container[i];
|
480
|
-
if (t && Array.isArray(t)) {
|
481
|
-
if (t[1] === 'ruleset') {
|
482
|
-
t[0].shortGroupID = this.shortGroupID++;
|
483
|
-
s = t[2];
|
484
|
-
if (s.length > 3) {
|
485
|
-
sr = s.slice(0, 2);
|
486
|
-
for (var k = s.length - 1; k > 1; k--) {
|
487
|
-
r = this.copyArray(t);
|
488
|
-
r[2] = sr.concat([s[k]]);
|
489
|
-
r[2][0].s = s[k][0].s;
|
490
|
-
container.splice(i + 1, 0, r);
|
491
|
-
}
|
492
|
-
container.splice(i, 1);
|
493
|
-
}
|
494
|
-
}
|
495
|
-
}
|
496
|
-
if (this.isContainer(t)) this.disjoin(t);
|
497
|
-
}
|
498
|
-
};
|
499
|
-
|
500
|
-
CSSOCompressor.prototype.walk = function(rules, container, path) {
|
501
|
-
var t, x;
|
502
|
-
for (var i = container.length - 1; i > -1; i--) {
|
503
|
-
t = container[i];
|
504
|
-
if (t && Array.isArray(t)) {
|
505
|
-
t[0].parent = container;
|
506
|
-
if (this.isContainer(t)) t = this.walk(rules, t, path + '/' + i); // go inside
|
507
|
-
if (t === null) container.splice(i, 1);
|
508
|
-
else {
|
509
|
-
if (x = this.process(rules, t, container, i, path)) container[i] = x; // compressed not null
|
510
|
-
else if (x === null) container.splice(i, 1); // null is the mark to delete token
|
511
|
-
}
|
512
|
-
}
|
513
|
-
}
|
514
|
-
return container.length ? container : null;
|
515
|
-
};
|
516
|
-
|
517
|
-
CSSOCompressor.prototype.freezeRulesets = function(token, rule, container, i) {
|
518
|
-
var info = token[0],
|
519
|
-
selector = token[2];
|
520
|
-
|
521
|
-
info.freeze = this.freezeNeeded(selector);
|
522
|
-
info.freezeID = this.selectorSignature(selector);
|
523
|
-
info.pseudoID = this.composePseudoID(selector);
|
524
|
-
this.markSimplePseudo(selector);
|
525
|
-
|
526
|
-
return token;
|
527
|
-
};
|
528
|
-
|
529
|
-
CSSOCompressor.prototype.markSimplePseudo = function(selector) {
|
530
|
-
var ss, sg = {};
|
531
|
-
|
532
|
-
for (var i = 2; i < selector.length; i++) {
|
533
|
-
ss = selector[i];
|
534
|
-
ss[0].pseudo = this.containsPseudo(ss);
|
535
|
-
ss[0].sg = sg;
|
536
|
-
sg[ss[0].s] = 1;
|
537
|
-
}
|
538
|
-
};
|
539
|
-
|
540
|
-
CSSOCompressor.prototype.composePseudoID = function(selector) {
|
541
|
-
var a = [], ss;
|
542
|
-
|
543
|
-
for (var i = 2; i < selector.length; i++) {
|
544
|
-
ss = selector[i];
|
545
|
-
if (this.containsPseudo(ss)) {
|
546
|
-
a.push(ss[0].s);
|
547
|
-
}
|
548
|
-
}
|
549
|
-
|
550
|
-
a.sort();
|
551
|
-
|
552
|
-
return a.join(',');
|
553
|
-
};
|
554
|
-
|
555
|
-
CSSOCompressor.prototype.containsPseudo = function(sselector) {
|
556
|
-
for (var j = 2; j < sselector.length; j++) {
|
557
|
-
switch (sselector[j][1]) {
|
558
|
-
case 'pseudoc':
|
559
|
-
case 'pseudoe':
|
560
|
-
case 'nthselector':
|
561
|
-
if (!(sselector[j][2][2] in this.notFPClasses)) return true;
|
562
|
-
}
|
563
|
-
}
|
564
|
-
};
|
565
|
-
|
566
|
-
CSSOCompressor.prototype.selectorSignature = function(selector) {
|
567
|
-
var a = [];
|
568
|
-
|
569
|
-
for (var i = 2; i < selector.length; i++) {
|
570
|
-
a.push(translator.translate(cleanInfo(selector[i])));
|
571
|
-
}
|
572
|
-
|
573
|
-
a.sort();
|
574
|
-
|
575
|
-
return a.join(',');
|
576
|
-
};
|
577
|
-
|
578
|
-
CSSOCompressor.prototype.pseudoSelectorSignature = function(selector, exclude) {
|
579
|
-
var a = [], b = {}, ss, wasExclude = false;
|
580
|
-
exclude = exclude || {};
|
581
|
-
|
582
|
-
for (var i = 2; i < selector.length; i++) {
|
583
|
-
ss = selector[i];
|
584
|
-
for (var j = 2; j < ss.length; j++) {
|
585
|
-
switch (ss[j][1]) {
|
586
|
-
case 'pseudoc':
|
587
|
-
case 'pseudoe':
|
588
|
-
case 'nthselector':
|
589
|
-
if (!(ss[j][2][2] in exclude)) b[ss[j][2][2]] = 1;
|
590
|
-
else wasExclude = true;
|
591
|
-
break;
|
592
|
-
}
|
593
|
-
}
|
594
|
-
}
|
595
|
-
|
596
|
-
for (var k in b) a.push(k);
|
597
|
-
|
598
|
-
a.sort();
|
599
|
-
|
600
|
-
return a.join(',') + wasExclude;
|
601
|
-
};
|
602
|
-
|
603
|
-
CSSOCompressor.prototype.notFPClasses = {
|
604
|
-
'link': 1,
|
605
|
-
'visited': 1,
|
606
|
-
'hover': 1,
|
607
|
-
'active': 1,
|
608
|
-
'first-letter': 1,
|
609
|
-
'first-line': 1
|
610
|
-
};
|
611
|
-
|
612
|
-
CSSOCompressor.prototype.notFPElements = {
|
613
|
-
'first-letter': 1,
|
614
|
-
'first-line': 1
|
615
|
-
};
|
616
|
-
|
617
|
-
CSSOCompressor.prototype.freezeNeeded = function(selector) {
|
618
|
-
var ss;
|
619
|
-
for (var i = 2; i < selector.length; i++) {
|
620
|
-
ss = selector[i];
|
621
|
-
for (var j = 2; j < ss.length; j++) {
|
622
|
-
switch (ss[j][1]) {
|
623
|
-
case 'pseudoc':
|
624
|
-
if (!(ss[j][2][2] in this.notFPClasses)) return true;
|
625
|
-
break;
|
626
|
-
case 'pseudoe':
|
627
|
-
if (!(ss[j][2][2] in this.notFPElements)) return true;
|
628
|
-
break;
|
629
|
-
case 'nthselector':
|
630
|
-
return true;
|
631
|
-
break;
|
632
|
-
}
|
633
|
-
}
|
634
|
-
}
|
635
|
-
return false;
|
636
|
-
};
|
637
|
-
|
638
|
-
CSSOCompressor.prototype.cleanCharset = function(token, rule, container, i) {
|
639
|
-
if (token[2][2][2] === 'charset') {
|
640
|
-
for (i = i - 1; i > 1; i--) {
|
641
|
-
if (container[i][1] !== 's' && container[i][1] !== 'comment') return null;
|
642
|
-
}
|
643
|
-
}
|
644
|
-
};
|
645
|
-
|
646
|
-
CSSOCompressor.prototype.cleanImport = function(token, rule, container, i) {
|
647
|
-
var x;
|
648
|
-
for (i = i - 1; i > 1; i--) {
|
649
|
-
x = container[i][1];
|
650
|
-
if (x !== 's' && x !== 'comment') {
|
651
|
-
if (x === 'atrules') {
|
652
|
-
x = container[i][2][2][2];
|
653
|
-
if (x !== 'import' && x !== 'charset') return null;
|
654
|
-
} else return null;
|
655
|
-
}
|
656
|
-
}
|
657
|
-
};
|
658
|
-
|
659
|
-
CSSOCompressor.prototype.cleanComment = function(token, rule, container, i) {
|
660
|
-
var pr = ((container[1] === 'braces' && i === 4) ||
|
661
|
-
(container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
|
662
|
-
nr = i === container.length - 1 ? null : container[i + 1][1];
|
663
|
-
|
664
|
-
if (nr !== null && pr !== null) {
|
665
|
-
if (this._cleanComment(nr) || this._cleanComment(pr)) return null;
|
666
|
-
} else return null;
|
667
|
-
};
|
668
|
-
|
669
|
-
CSSOCompressor.prototype._cleanComment = function(r) {
|
670
|
-
switch(r) {
|
671
|
-
case 's':
|
672
|
-
case 'operator':
|
673
|
-
case 'attrselector':
|
674
|
-
case 'block':
|
675
|
-
case 'decldelim':
|
676
|
-
case 'ruleset':
|
677
|
-
case 'declaration':
|
678
|
-
case 'atruleb':
|
679
|
-
case 'atrules':
|
680
|
-
case 'atruler':
|
681
|
-
case 'important':
|
682
|
-
case 'nth':
|
683
|
-
case 'combinator':
|
684
|
-
return true;
|
685
|
-
}
|
686
|
-
};
|
687
|
-
|
688
|
-
CSSOCompressor.prototype.nextToken = function(container, type, i, exactly) {
|
689
|
-
var t, r;
|
690
|
-
for (; i < container.length; i++) {
|
691
|
-
t = container[i];
|
692
|
-
if (Array.isArray(t)) {
|
693
|
-
r = t[1];
|
694
|
-
if (r === type) return t;
|
695
|
-
else if (exactly && r !== 's') return;
|
696
|
-
}
|
697
|
-
}
|
698
|
-
};
|
699
|
-
|
700
|
-
CSSOCompressor.prototype.cleanWhitespace = function(token, rule, container, i) {
|
701
|
-
var pr = ((container[1] === 'braces' && i === 4) ||
|
702
|
-
(container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
|
703
|
-
nr = i === container.length - 1 ? null : container[i + 1][1];
|
704
|
-
|
705
|
-
if (nr === 'unknown') token[2] = '\n';
|
706
|
-
else {
|
707
|
-
if (!(container[1] === 'atrulerq' && !pr) && !this.issue16(container, i)) {
|
708
|
-
if (nr !== null && pr !== null) {
|
709
|
-
if (this._cleanWhitespace(nr, false) || this._cleanWhitespace(pr, true)) return null;
|
710
|
-
} else return null;
|
711
|
-
}
|
712
|
-
|
713
|
-
token[2] = ' ';
|
714
|
-
}
|
715
|
-
|
716
|
-
return token;
|
717
|
-
};
|
718
|
-
|
719
|
-
// See https://github.com/afelix/csso/issues/16
|
720
|
-
CSSOCompressor.prototype.issue16 = function(container, i) {
|
721
|
-
return (i !== 2 && i !== container.length - 1 && container[i - 1][1] === 'uri');
|
722
|
-
};
|
723
|
-
|
724
|
-
CSSOCompressor.prototype._cleanWhitespace = function(r, left) {
|
725
|
-
switch(r) {
|
726
|
-
case 's':
|
727
|
-
case 'operator':
|
728
|
-
case 'attrselector':
|
729
|
-
case 'block':
|
730
|
-
case 'decldelim':
|
731
|
-
case 'ruleset':
|
732
|
-
case 'declaration':
|
733
|
-
case 'atruleb':
|
734
|
-
case 'atrules':
|
735
|
-
case 'atruler':
|
736
|
-
case 'important':
|
737
|
-
case 'nth':
|
738
|
-
case 'combinator':
|
739
|
-
return true;
|
740
|
-
}
|
741
|
-
if (left) {
|
742
|
-
switch(r) {
|
743
|
-
case 'funktion':
|
744
|
-
case 'braces':
|
745
|
-
case 'uri':
|
746
|
-
return true;
|
747
|
-
}
|
748
|
-
}
|
749
|
-
};
|
750
|
-
|
751
|
-
CSSOCompressor.prototype.cleanDecldelim = function(token) {
|
752
|
-
for (var i = token.length - 1; i > 1; i--) {
|
753
|
-
if (token[i][1] === 'decldelim' &&
|
754
|
-
token[i + 1][1] !== 'declaration') token.splice(i, 1);
|
755
|
-
}
|
756
|
-
if (token[2][1] === 'decldelim') token.splice(2, 1);
|
757
|
-
return token;
|
758
|
-
};
|
759
|
-
|
760
|
-
CSSOCompressor.prototype.compressNumber = function(token, rule, container, i) {
|
761
|
-
var x = token[2];
|
762
|
-
|
763
|
-
if (/^0*/.test(x)) x = x.replace(/^0+/, '');
|
764
|
-
if (/\.0*$/.test(x)) x = x.replace(/\.0*$/, '');
|
765
|
-
if (/\..*[1-9]+0+$/.test(x)) x = x.replace(/0+$/, '');
|
766
|
-
if (x === '.' || x === '') x = '0';
|
767
|
-
|
768
|
-
token[2] = x;
|
769
|
-
token[0].s = x;
|
770
|
-
return token;
|
771
|
-
};
|
772
|
-
|
773
|
-
CSSOCompressor.prototype.findDeclaration = function(token) {
|
774
|
-
var parent = token;
|
775
|
-
while ((parent = parent[0].parent) && parent[1] !== 'declaration');
|
776
|
-
return parent;
|
777
|
-
};
|
778
|
-
|
779
|
-
CSSOCompressor.prototype.cleanUnary = function(token, rule, container, i) {
|
780
|
-
var next = container[i + 1];
|
781
|
-
if (next && next[1] === 'number' && next[2] === '0') return null;
|
782
|
-
return token;
|
783
|
-
};
|
784
|
-
|
785
|
-
CSSOCompressor.prototype.compressColor = function(token, rule, container, i) {
|
786
|
-
switch(rule) {
|
787
|
-
case 'vhash':
|
788
|
-
return this.compressHashColor(token);
|
789
|
-
case 'funktion':
|
790
|
-
return this.compressFunctionColor(token);
|
791
|
-
case 'ident':
|
792
|
-
return this.compressIdentColor(token, rule, container, i);
|
793
|
-
}
|
794
|
-
};
|
795
|
-
|
796
|
-
CSSOCompressor.prototype.compressIdentColor = function(token, rule, container) {
|
797
|
-
var map = { 'yellow': 'ff0',
|
798
|
-
'fuchsia': 'f0f',
|
799
|
-
'white': 'fff',
|
800
|
-
'black': '000',
|
801
|
-
'blue': '00f',
|
802
|
-
'aqua': '0ff' },
|
803
|
-
allow = { 'value': 1, 'functionBody': 1 },
|
804
|
-
_x = token[2].toLowerCase();
|
805
|
-
|
806
|
-
if (container[1] in allow && _x in map) return [{}, 'vhash', map[_x]];
|
807
|
-
};
|
808
|
-
|
809
|
-
CSSOCompressor.prototype.compressHashColor = function(token) {
|
810
|
-
return this._compressHashColor(token[2], token[0]);
|
811
|
-
};
|
812
|
-
|
813
|
-
CSSOCompressor.prototype._compressHashColor = function(x, info) {
|
814
|
-
var map = { 'f00': 'red',
|
815
|
-
'c0c0c0': 'silver',
|
816
|
-
'808080': 'gray',
|
817
|
-
'800000': 'maroon',
|
818
|
-
'800080': 'purple',
|
819
|
-
'008000': 'green',
|
820
|
-
'808000': 'olive',
|
821
|
-
'000080': 'navy',
|
822
|
-
'008080': 'teal'},
|
823
|
-
_x = x;
|
824
|
-
x = x.toLowerCase();
|
825
|
-
|
826
|
-
if (x.length === 6 &&
|
827
|
-
x.charAt(0) === x.charAt(1) &&
|
828
|
-
x.charAt(2) === x.charAt(3) &&
|
829
|
-
x.charAt(4) === x.charAt(5)) x = x.charAt(0) + x.charAt(2) + x.charAt(4);
|
830
|
-
|
831
|
-
return map[x] ? [info, 'string', map[x]] : [info, 'vhash', (x.length < _x.length ? x : _x)];
|
832
|
-
};
|
833
|
-
|
834
|
-
CSSOCompressor.prototype.compressFunctionColor = function(token) {
|
835
|
-
var i, v = [], t, h = '', body;
|
836
|
-
|
837
|
-
if (token[2][2] === 'rgb') {
|
838
|
-
body = token[3];
|
839
|
-
for (i = 2; i < body.length; i++) {
|
840
|
-
t = body[i][1];
|
841
|
-
if (t === 'number') v.push(body[i]);
|
842
|
-
else if (t !== 'operator') { v = []; break }
|
843
|
-
}
|
844
|
-
if (v.length === 3) {
|
845
|
-
h += (t = Number(v[0][2]).toString(16)).length === 1 ? '0' + t : t;
|
846
|
-
h += (t = Number(v[1][2]).toString(16)).length === 1 ? '0' + t : t;
|
847
|
-
h += (t = Number(v[2][2]).toString(16)).length === 1 ? '0' + t : t;
|
848
|
-
if (h.length === 6) return this._compressHashColor(h, {});
|
849
|
-
}
|
850
|
-
}
|
851
|
-
};
|
852
|
-
|
853
|
-
CSSOCompressor.prototype.compressDimension = function(token) {
|
854
|
-
var declaration;
|
855
|
-
if (token[2][2] === '0') {
|
856
|
-
if (token[3][2] === 's' && (declaration = this.findDeclaration(token))) {
|
857
|
-
var declName = declaration[2][2][2];
|
858
|
-
if (declName === '-moz-transition') return; // https://github.com/css/csso/issues/82
|
859
|
-
if (declName === '-moz-animation' || declName === 'animation') return; // https://github.com/css/csso/issues/100
|
860
|
-
}
|
861
|
-
return token[2];
|
862
|
-
}
|
863
|
-
};
|
864
|
-
|
865
|
-
CSSOCompressor.prototype.compressString = function(token, rule, container) {
|
866
|
-
var s = token[2], r = '', c;
|
867
|
-
for (var i = 0; i < s.length; i++) {
|
868
|
-
c = s.charAt(i);
|
869
|
-
if (c === '\\' && s.charAt(i + 1) === '\n') i++;
|
870
|
-
else r += c;
|
871
|
-
}
|
872
|
-
// if (container[1] === 'attrib' && /^('|")[a-zA-Z0-9]*('|")$/.test(r)) {
|
873
|
-
// r = r.substring(1, r.length - 1);
|
874
|
-
// }
|
875
|
-
if (s.length !== r.length) return [{}, 'string', r];
|
876
|
-
};
|
877
|
-
|
878
|
-
CSSOCompressor.prototype.compressFontWeight = function(token) {
|
879
|
-
var p = token[2],
|
880
|
-
v = token[3];
|
881
|
-
if (p[2][2].indexOf('font-weight') !== -1 && v[2][1] === 'ident') {
|
882
|
-
if (v[2][2] === 'normal') v[2] = [{}, 'number', '400'];
|
883
|
-
else if (v[2][2] === 'bold') v[2] = [{}, 'number', '700'];
|
884
|
-
return token;
|
885
|
-
}
|
886
|
-
};
|
887
|
-
|
888
|
-
CSSOCompressor.prototype.compressFont = function(token) {
|
889
|
-
var p = token[2],
|
890
|
-
v = token[3],
|
891
|
-
i, x, t;
|
892
|
-
if (/font$/.test(p[2][2]) && v.length) {
|
893
|
-
v.splice(2, 0, [{}, 's', '']);
|
894
|
-
for (i = v.length - 1; i > 2; i--) {
|
895
|
-
x = v[i];
|
896
|
-
if (x[1] === 'ident') {
|
897
|
-
x = x[2];
|
898
|
-
if (x === 'bold') v[i] = [{}, 'number', '700'];
|
899
|
-
else if (x === 'normal') {
|
900
|
-
t = v[i - 1];
|
901
|
-
if (t[1] === 'operator' && t[2] === '/') v.splice(--i, 2);
|
902
|
-
else v.splice(i, 1);
|
903
|
-
if (v[i - 1][1] === 's') v.splice(--i, 1);
|
904
|
-
}
|
905
|
-
else if (x === 'medium' && v[i + 1] && v[i + 1][2] !== '/') {
|
906
|
-
v.splice(i, 1);
|
907
|
-
if (v[i - 1][1] === 's') v.splice(--i, 1);
|
908
|
-
}
|
909
|
-
}
|
910
|
-
}
|
911
|
-
if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
|
912
|
-
if (v.length === 2) v.push([{}, 'ident', 'normal']);
|
913
|
-
return token;
|
914
|
-
}
|
915
|
-
};
|
916
|
-
|
917
|
-
CSSOCompressor.prototype.compressBackground = function(token) {
|
918
|
-
var p = token[2],
|
919
|
-
v = token[3],
|
920
|
-
i, x, t,
|
921
|
-
n = v[v.length - 1][1] === 'important' ? 3 : 2;
|
922
|
-
if (/background$/.test(p[2][2]) && v.length) {
|
923
|
-
v.splice(2, 0, [{}, 's', '']);
|
924
|
-
for (i = v.length - 1; i > n; i--) {
|
925
|
-
x = v[i];
|
926
|
-
if (x[1] === 'ident') {
|
927
|
-
x = x[2];
|
928
|
-
if (x === 'transparent' || x === 'none' || x === 'repeat' || x === 'scroll') {
|
929
|
-
v.splice(i, 1);
|
930
|
-
if (v[i - 1][1] === 's') v.splice(--i, 1);
|
931
|
-
}
|
932
|
-
}
|
933
|
-
}
|
934
|
-
if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
|
935
|
-
if (v.length === 2) v.splice(2, 0, [{}, 'number', '0'], [{}, 's', ' '], [{}, 'number', '0']);
|
936
|
-
return token;
|
937
|
-
}
|
938
|
-
};
|
939
|
-
|
940
|
-
CSSOCompressor.prototype.cleanEmpty = function(token, rule) {
|
941
|
-
switch(rule) {
|
942
|
-
case 'ruleset':
|
943
|
-
if (token[3].length === 2) return null;
|
944
|
-
break;
|
945
|
-
case 'atruleb':
|
946
|
-
if (token[token.length - 1].length < 3) return null;
|
947
|
-
break;
|
948
|
-
case 'atruler':
|
949
|
-
if (token[4].length < 3) return null;
|
950
|
-
break;
|
951
|
-
}
|
952
|
-
};
|
953
|
-
|
954
|
-
CSSOCompressor.prototype.destroyDelims = function() {
|
955
|
-
return null;
|
956
|
-
};
|
957
|
-
|
958
|
-
CSSOCompressor.prototype.preTranslate = function(token) {
|
959
|
-
token[0].s = translator.translate(cleanInfo(token));
|
960
|
-
return token;
|
961
|
-
};
|
962
|
-
|
963
|
-
CSSOCompressor.prototype.markShorthands = function(token, rule, container, j, path) {
|
964
|
-
if (container[1] === 'ruleset') {
|
965
|
-
var selector = container[2][2][0].s,
|
966
|
-
freeze = container[0].freeze,
|
967
|
-
freezeID = container[0].freezeID;
|
968
|
-
} else {
|
969
|
-
var selector = '',
|
970
|
-
freeze = false,
|
971
|
-
freezeID = 'fake';
|
972
|
-
}
|
973
|
-
var x, p, v, imp, s, key, sh,
|
974
|
-
pre = this.pathUp(path) + '/' + (freeze ? '&' + freezeID + '&' : '') + selector + '/',
|
975
|
-
createNew, shortsI, shortGroupID = container[0].shortGroupID;
|
976
|
-
|
977
|
-
for (var i = token.length - 1; i > -1; i--) {
|
978
|
-
createNew = true;
|
979
|
-
x = token[i];
|
980
|
-
if (x[1] === 'declaration') {
|
981
|
-
v = x[3];
|
982
|
-
imp = v[v.length - 1][1] === 'important';
|
983
|
-
p = x[2][0].s;
|
984
|
-
x[0].id = path + '/' + i;
|
985
|
-
if (p in TRBL.props) {
|
986
|
-
key = pre + TRBL.extractMain(p);
|
987
|
-
var shorts = this.shorts2[key] || [];
|
988
|
-
shortsI = shorts.length === 0 ? 0 : shorts.length - 1;
|
989
|
-
|
990
|
-
if (!this.lastShortSelector || selector === this.lastShortSelector || shortGroupID === this.lastShortGroupID) {
|
991
|
-
if (shorts.length) {
|
992
|
-
sh = shorts[shortsI];
|
993
|
-
//if (imp && !sh.imp) sh.invalid = true;
|
994
|
-
createNew = false;
|
995
|
-
}
|
996
|
-
}
|
997
|
-
|
998
|
-
if (createNew) {
|
999
|
-
x[0].replaceByShort = true;
|
1000
|
-
x[0].shorthandKey = { key: key, i: shortsI };
|
1001
|
-
sh = new TRBL(p, imp);
|
1002
|
-
shorts.push(sh);
|
1003
|
-
}
|
1004
|
-
|
1005
|
-
if (!sh.invalid) {
|
1006
|
-
x[0].removeByShort = true;
|
1007
|
-
x[0].shorthandKey = { key: key, i: shortsI };
|
1008
|
-
sh.add(p, v[0].s, v.slice(2), imp);
|
1009
|
-
}
|
1010
|
-
|
1011
|
-
this.shorts2[key] = shorts;
|
1012
|
-
|
1013
|
-
this.lastShortSelector = selector;
|
1014
|
-
this.lastShortGroupID = shortGroupID;
|
1015
|
-
}
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
|
1019
|
-
|
1020
|
-
return token;
|
1021
|
-
};
|
1022
|
-
|
1023
|
-
CSSOCompressor.prototype.cleanShorthands = function(token) {
|
1024
|
-
if (token[0].removeByShort || token[0].replaceByShort) {
|
1025
|
-
var s, t, sKey = token[0].shorthandKey;
|
1026
|
-
|
1027
|
-
s = this.shorts2[sKey.key][sKey.i];
|
1028
|
-
|
1029
|
-
if (!s.invalid && s.isOkToMinimize()) {
|
1030
|
-
if (token[0].replaceByShort) {
|
1031
|
-
t = [{}, 'declaration', s.getProperty(), s.getValue()];
|
1032
|
-
t[0].s = translator.translate(cleanInfo(t));
|
1033
|
-
return t;
|
1034
|
-
} else return null;
|
1035
|
-
}
|
1036
|
-
}
|
1037
|
-
};
|
1038
|
-
|
1039
|
-
CSSOCompressor.prototype.dontRestructure = {
|
1040
|
-
'src': 1, // https://github.com/afelix/csso/issues/50
|
1041
|
-
'clip': 1, // https://github.com/afelix/csso/issues/57
|
1042
|
-
'display': 1 // https://github.com/afelix/csso/issues/71
|
1043
|
-
};
|
1044
|
-
|
1045
|
-
CSSOCompressor.prototype.restructureBlock = function(token, rule, container, j, path) {
|
1046
|
-
if (container[1] === 'ruleset') {
|
1047
|
-
var props = this.props,
|
1048
|
-
isPseudo = container[2][2][0].pseudo,
|
1049
|
-
selector = container[2][2][0].s,
|
1050
|
-
freeze = container[0].freeze,
|
1051
|
-
freezeID = container[0].freezeID,
|
1052
|
-
pseudoID = container[0].pseudoID,
|
1053
|
-
sg = container[2][2][0].sg;
|
1054
|
-
} else {
|
1055
|
-
var props = {},
|
1056
|
-
isPseudo = false,
|
1057
|
-
selector = '',
|
1058
|
-
freeze = false,
|
1059
|
-
freezeID = 'fake',
|
1060
|
-
pseudoID = 'fake',
|
1061
|
-
sg = {};
|
1062
|
-
}
|
1063
|
-
|
1064
|
-
var x, p, v, imp, t,
|
1065
|
-
pre = this.pathUp(path) + '/' + selector + '/',
|
1066
|
-
ppre;
|
1067
|
-
|
1068
|
-
for (var i = token.length - 1; i > -1; i--) {
|
1069
|
-
x = token[i];
|
1070
|
-
if (x[1] === 'declaration') {
|
1071
|
-
v = x[3];
|
1072
|
-
imp = v[v.length - 1][1] === 'important';
|
1073
|
-
p = x[2][0].s;
|
1074
|
-
ppre = this.buildPPre(pre, p, v, x, freeze);
|
1075
|
-
x[0].id = path + '/' + i;
|
1076
|
-
if (!this.dontRestructure[p] && (t = props[ppre])) {
|
1077
|
-
if ((isPseudo && freezeID === t.freezeID) || // pseudo from equal selectors group
|
1078
|
-
(!isPseudo && pseudoID === t.pseudoID) || // not pseudo from equal pseudo signature group
|
1079
|
-
(isPseudo && pseudoID === t.pseudoID && this.hashInHash(sg, t.sg))) { // pseudo from covered selectors group
|
1080
|
-
if (imp && !t.imp) {
|
1081
|
-
props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
|
1082
|
-
freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
|
1083
|
-
this.deleteProperty(t.block, t.id);
|
1084
|
-
} else {
|
1085
|
-
token.splice(i, 1);
|
1086
|
-
}
|
1087
|
-
}
|
1088
|
-
} else if (this.needless(p, props, pre, imp, v, x, freeze)) {
|
1089
|
-
token.splice(i, 1);
|
1090
|
-
} else {
|
1091
|
-
props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
|
1092
|
-
freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
|
1093
|
-
}
|
1094
|
-
}
|
1095
|
-
}
|
1096
|
-
return token;
|
1097
|
-
};
|
1098
|
-
|
1099
|
-
CSSOCompressor.prototype.buildPPre = function(pre, p, v, d, freeze) {
|
1100
|
-
var fp = freeze ? 'ft:' : 'ff:';
|
1101
|
-
if (p.indexOf('background') !== -1) return fp + pre + d[0].s;
|
1102
|
-
|
1103
|
-
var _v = v.slice(2),
|
1104
|
-
colorMark = [
|
1105
|
-
0, // ident, vhash, rgb
|
1106
|
-
0, // hsl
|
1107
|
-
0, // hsla
|
1108
|
-
0 // rgba
|
1109
|
-
],
|
1110
|
-
vID = '';
|
1111
|
-
|
1112
|
-
for (var i = 0; i < _v.length; i++) {
|
1113
|
-
if (!vID) vID = this.getVendorIDFromToken(_v[i]);
|
1114
|
-
switch(_v[i][1]) {
|
1115
|
-
case 'vhash':
|
1116
|
-
case 'ident':
|
1117
|
-
colorMark[0] = 1; break;
|
1118
|
-
case 'funktion':
|
1119
|
-
switch(_v[i][2][2]) {
|
1120
|
-
case 'rgb':
|
1121
|
-
colorMark[0] = 1; break;
|
1122
|
-
case 'hsl':
|
1123
|
-
colorMark[1] = 1; break;
|
1124
|
-
case 'hsla':
|
1125
|
-
colorMark[2] = 1; break;
|
1126
|
-
case 'rgba':
|
1127
|
-
colorMark[3] = 1; break;
|
1128
|
-
}
|
1129
|
-
break;
|
1130
|
-
}
|
1131
|
-
}
|
1132
|
-
|
1133
|
-
return fp + pre + p + colorMark.join('') + (vID ? vID : '');
|
1134
|
-
};
|
1135
|
-
|
1136
|
-
CSSOCompressor.prototype.vendorID = {
|
1137
|
-
'-o-': 'o',
|
1138
|
-
'-moz-': 'm',
|
1139
|
-
'-webkit-': 'w',
|
1140
|
-
'-ms-': 'i',
|
1141
|
-
'-epub-': 'e',
|
1142
|
-
'-apple-': 'a',
|
1143
|
-
'-xv-': 'x',
|
1144
|
-
'-wap-': 'p'
|
1145
|
-
};
|
1146
|
-
|
1147
|
-
CSSOCompressor.prototype.getVendorIDFromToken = function(token) {
|
1148
|
-
var vID;
|
1149
|
-
switch(token[1]) {
|
1150
|
-
case 'ident':
|
1151
|
-
if (vID = this.getVendorFromString(token[2])) return this.vendorID[vID];
|
1152
|
-
break;
|
1153
|
-
case 'funktion':
|
1154
|
-
if (vID = this.getVendorFromString(token[2][2])) return this.vendorID[vID];
|
1155
|
-
break;
|
1156
|
-
}
|
1157
|
-
};
|
1158
|
-
|
1159
|
-
CSSOCompressor.prototype.getVendorFromString = function(string) {
|
1160
|
-
var vendor = string.charAt(0), i;
|
1161
|
-
if (vendor === '-') {
|
1162
|
-
if ((i = string.indexOf('-', 2)) !== -1) return string.substr(0, i + 1);
|
1163
|
-
}
|
1164
|
-
return '';
|
1165
|
-
};
|
1166
|
-
|
1167
|
-
CSSOCompressor.prototype.deleteProperty = function(block, id) {
|
1168
|
-
var d;
|
1169
|
-
for (var i = block.length - 1; i > 1; i--) {
|
1170
|
-
d = block[i];
|
1171
|
-
if (Array.isArray(d) && d[1] === 'declaration' && d[0].id === id) {
|
1172
|
-
block.splice(i, 1);
|
1173
|
-
return;
|
1174
|
-
}
|
1175
|
-
}
|
1176
|
-
};
|
1177
|
-
|
1178
|
-
CSSOCompressor.prototype.nlTable = {
|
1179
|
-
'border-width': ['border'],
|
1180
|
-
'border-style': ['border'],
|
1181
|
-
'border-color': ['border'],
|
1182
|
-
'border-top': ['border'],
|
1183
|
-
'border-right': ['border'],
|
1184
|
-
'border-bottom': ['border'],
|
1185
|
-
'border-left': ['border'],
|
1186
|
-
'border-top-width': ['border-top', 'border-width', 'border'],
|
1187
|
-
'border-right-width': ['border-right', 'border-width', 'border'],
|
1188
|
-
'border-bottom-width': ['border-bottom', 'border-width', 'border'],
|
1189
|
-
'border-left-width': ['border-left', 'border-width', 'border'],
|
1190
|
-
'border-top-style': ['border-top', 'border-style', 'border'],
|
1191
|
-
'border-right-style': ['border-right', 'border-style', 'border'],
|
1192
|
-
'border-bottom-style': ['border-bottom', 'border-style', 'border'],
|
1193
|
-
'border-left-style': ['border-left', 'border-style', 'border'],
|
1194
|
-
'border-top-color': ['border-top', 'border-color', 'border'],
|
1195
|
-
'border-right-color': ['border-right', 'border-color', 'border'],
|
1196
|
-
'border-bottom-color': ['border-bottom', 'border-color', 'border'],
|
1197
|
-
'border-left-color': ['border-left', 'border-color', 'border'],
|
1198
|
-
'margin-top': ['margin'],
|
1199
|
-
'margin-right': ['margin'],
|
1200
|
-
'margin-bottom': ['margin'],
|
1201
|
-
'margin-left': ['margin'],
|
1202
|
-
'padding-top': ['padding'],
|
1203
|
-
'padding-right': ['padding'],
|
1204
|
-
'padding-bottom': ['padding'],
|
1205
|
-
'padding-left': ['padding'],
|
1206
|
-
'font-style': ['font'],
|
1207
|
-
'font-variant': ['font'],
|
1208
|
-
'font-weight': ['font'],
|
1209
|
-
'font-size': ['font'],
|
1210
|
-
'font-family': ['font'],
|
1211
|
-
'list-style-type': ['list-style'],
|
1212
|
-
'list-style-position': ['list-style'],
|
1213
|
-
'list-style-image': ['list-style']
|
1214
|
-
};
|
1215
|
-
|
1216
|
-
CSSOCompressor.prototype.needless = function(name, props, pre, imp, v, d, freeze) {
|
1217
|
-
var hack = name.charAt(0);
|
1218
|
-
if (hack === '*' || hack === '_' || hack === '$') name = name.substr(1);
|
1219
|
-
else if (hack === '/' && name.charAt(1) === '/') {
|
1220
|
-
hack = '//';
|
1221
|
-
name = name.substr(2);
|
1222
|
-
} else hack = '';
|
1223
|
-
|
1224
|
-
var vendor = this.getVendorFromString(name),
|
1225
|
-
prop = name.substr(vendor.length),
|
1226
|
-
x, t, ppre;
|
1227
|
-
|
1228
|
-
if (prop in this.nlTable) {
|
1229
|
-
x = this.nlTable[prop];
|
1230
|
-
for (var i = 0; i < x.length; i++) {
|
1231
|
-
ppre = this.buildPPre(pre, hack + vendor + x[i], v, d, freeze);
|
1232
|
-
if (t = props[ppre]) return (!imp || t.imp);
|
1233
|
-
}
|
1234
|
-
}
|
1235
|
-
};
|
1236
|
-
|
1237
|
-
CSSOCompressor.prototype.rejoinRuleset = function(token, rule, container, i) {
|
1238
|
-
var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
|
1239
|
-
ps = p ? p[2].slice(2) : [],
|
1240
|
-
pb = p ? p[3].slice(2) : [],
|
1241
|
-
ts = token[2].slice(2),
|
1242
|
-
tb = token[3].slice(2),
|
1243
|
-
ph, th, r;
|
1244
|
-
|
1245
|
-
if (!tb.length) return null;
|
1246
|
-
|
1247
|
-
if (ps.length && pb.length) {
|
1248
|
-
if (token[1] !== p[1]) return;
|
1249
|
-
// try to join by selectors
|
1250
|
-
ph = this.getHash(ps);
|
1251
|
-
th = this.getHash(ts);
|
1252
|
-
|
1253
|
-
if (this.equalHash(th, ph)) {
|
1254
|
-
p[3] = p[3].concat(token[3].splice(2));
|
1255
|
-
return null;
|
1256
|
-
}
|
1257
|
-
if (this.okToJoinByProperties(token, p)) {
|
1258
|
-
// try to join by properties
|
1259
|
-
r = this.analyze(token, p);
|
1260
|
-
if (!r.ne1.length && !r.ne2.length) {
|
1261
|
-
p[2] = this.cleanSelector(p[2].concat(token[2].splice(2)));
|
1262
|
-
p[2][0].s = translator.translate(cleanInfo(p[2]));
|
1263
|
-
return null;
|
1264
|
-
}
|
1265
|
-
}
|
1266
|
-
}
|
1267
|
-
};
|
1268
|
-
|
1269
|
-
CSSOCompressor.prototype.okToJoinByProperties = function(r0, r1) {
|
1270
|
-
var i0 = r0[0], i1 = r1[0];
|
1271
|
-
|
1272
|
-
// same frozen ruleset
|
1273
|
-
if (i0.freezeID === i1.freezeID) return true;
|
1274
|
-
|
1275
|
-
// same pseudo-classes in selectors
|
1276
|
-
if (i0.pseudoID === i1.pseudoID) return true;
|
1277
|
-
|
1278
|
-
// different frozen rulesets
|
1279
|
-
if (i0.freeze && i1.freeze) {
|
1280
|
-
return this.pseudoSelectorSignature(r0[2], this.allowedPClasses) === this.pseudoSelectorSignature(r1[2], this.allowedPClasses);
|
1281
|
-
}
|
1282
|
-
|
1283
|
-
// is it frozen at all?
|
1284
|
-
return !(i0.freeze || i1.freeze);
|
1285
|
-
};
|
1286
|
-
|
1287
|
-
CSSOCompressor.prototype.allowedPClasses = {
|
1288
|
-
'after': 1,
|
1289
|
-
'before': 1
|
1290
|
-
};
|
1291
|
-
|
1292
|
-
CSSOCompressor.prototype.containsOnlyAllowedPClasses = function(selector) {
|
1293
|
-
var ss;
|
1294
|
-
for (var i = 2; i < selector.length; i++) {
|
1295
|
-
ss = selector[i];
|
1296
|
-
for (var j = 2; j < ss.length; j++) {
|
1297
|
-
if (ss[j][1] == 'pseudoc' || ss[j][1] == 'pseudoe') {
|
1298
|
-
if (!(ss[j][2][2] in this.allowedPClasses)) return false;
|
1299
|
-
}
|
1300
|
-
}
|
1301
|
-
}
|
1302
|
-
return true;
|
1303
|
-
};
|
1304
|
-
|
1305
|
-
CSSOCompressor.prototype.restructureRuleset = function(token, rule, container, i) {
|
1306
|
-
var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
|
1307
|
-
ps = p ? p[2].slice(2) : [],
|
1308
|
-
pb = p ? p[3].slice(2) : [],
|
1309
|
-
tb = token[3].slice(2),
|
1310
|
-
r, nr;
|
1311
|
-
|
1312
|
-
if (!tb.length) return null;
|
1313
|
-
|
1314
|
-
if (ps.length && pb.length) {
|
1315
|
-
if (token[1] !== p[1]) return;
|
1316
|
-
// try to join by properties
|
1317
|
-
r = this.analyze(token, p);
|
1318
|
-
|
1319
|
-
if (r.eq.length && (r.ne1.length || r.ne2.length)) {
|
1320
|
-
if (r.ne1.length && !r.ne2.length) { // p in token
|
1321
|
-
var ns = token[2].slice(2), // TODO: copypaste
|
1322
|
-
nss = translator.translate(cleanInfo(token[2])),
|
1323
|
-
sl = nss.length + // selector length
|
1324
|
-
ns.length - 1, // delims length
|
1325
|
-
bl = this.calcLength(r.eq) + // declarations length
|
1326
|
-
r.eq.length - 1; // decldelims length
|
1327
|
-
if (sl < bl) {
|
1328
|
-
p[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
|
1329
|
-
token[3].splice(2);
|
1330
|
-
token[3] = token[3].concat(r.ne1);
|
1331
|
-
return token;
|
1332
|
-
}
|
1333
|
-
} else if (r.ne2.length && !r.ne1.length) { // token in p
|
1334
|
-
var ns = p[2].slice(2),
|
1335
|
-
nss = translator.translate(cleanInfo(p[2])),
|
1336
|
-
sl = nss.length + // selector length
|
1337
|
-
ns.length - 1, // delims length
|
1338
|
-
bl = this.calcLength(r.eq) + // declarations length
|
1339
|
-
r.eq.length - 1; // decldelims length
|
1340
|
-
if (sl < bl) {
|
1341
|
-
token[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
|
1342
|
-
p[3].splice(2);
|
1343
|
-
p[3] = p[3].concat(r.ne2);
|
1344
|
-
return token;
|
1345
|
-
}
|
1346
|
-
} else { // extract equal block?
|
1347
|
-
var ns = this.cleanSelector(p[2].concat(token[2].slice(2))),
|
1348
|
-
nss = translator.translate(cleanInfo(ns)),
|
1349
|
-
rl = nss.length + // selector length
|
1350
|
-
ns.length - 1 + // delims length
|
1351
|
-
2, // braces length
|
1352
|
-
bl = this.calcLength(r.eq) + // declarations length
|
1353
|
-
r.eq.length - 1; // decldelims length
|
1354
|
-
|
1355
|
-
if (bl >= rl) { // ok, it's good enough to extract
|
1356
|
-
ns[0].s = nss;
|
1357
|
-
nr = [{f:0, l:0}, 'ruleset', ns, [{f:0,l:0}, 'block'].concat(r.eq)];
|
1358
|
-
token[3].splice(2);
|
1359
|
-
token[3] = token[3].concat(r.ne1);
|
1360
|
-
p[3].splice(2);
|
1361
|
-
p[3] = p[3].concat(r.ne2);
|
1362
|
-
container.splice(i, 0, nr);
|
1363
|
-
return nr;
|
1364
|
-
}
|
1365
|
-
}
|
1366
|
-
}
|
1367
|
-
}
|
1368
|
-
};
|
1369
|
-
|
1370
|
-
CSSOCompressor.prototype.calcLength = function(tokens) {
|
1371
|
-
var r = 0;
|
1372
|
-
for (var i = 0; i < tokens.length; i++) r += tokens[i][0].s.length;
|
1373
|
-
return r;
|
1374
|
-
};
|
1375
|
-
|
1376
|
-
CSSOCompressor.prototype.cleanSelector = function(token) {
|
1377
|
-
if (token.length === 2) return null;
|
1378
|
-
var h = {}, s;
|
1379
|
-
for (var i = 2; i < token.length; i++) {
|
1380
|
-
s = token[i][0].s;
|
1381
|
-
if (s in h) token.splice(i, 1), i--;
|
1382
|
-
else h[s] = 1;
|
1383
|
-
}
|
1384
|
-
|
1385
|
-
return token;
|
1386
|
-
};
|
1387
|
-
|
1388
|
-
CSSOCompressor.prototype.analyze = function(r1, r2) {
|
1389
|
-
var r = { eq: [], ne1: [], ne2: [] };
|
1390
|
-
|
1391
|
-
if (r1[1] !== r2[1]) return r;
|
1392
|
-
|
1393
|
-
var b1 = r1[3], b2 = r2[3],
|
1394
|
-
d1 = b1.slice(2), d2 = b2.slice(2),
|
1395
|
-
h1, h2, i, x;
|
1396
|
-
|
1397
|
-
h1 = this.getHash(d1);
|
1398
|
-
h2 = this.getHash(d2);
|
1399
|
-
|
1400
|
-
for (i = 0; i < d1.length; i++) {
|
1401
|
-
x = d1[i];
|
1402
|
-
if (x[0].s in h2) r.eq.push(x);
|
1403
|
-
else r.ne1.push(x);
|
1404
|
-
}
|
1405
|
-
|
1406
|
-
for (i = 0; i < d2.length; i++) {
|
1407
|
-
x = d2[i];
|
1408
|
-
if (!(x[0].s in h1)) r.ne2.push(x);
|
1409
|
-
}
|
1410
|
-
|
1411
|
-
return r;
|
1412
|
-
};
|
1413
|
-
|
1414
|
-
CSSOCompressor.prototype.equalHash = function(h0, h1) {
|
1415
|
-
var k;
|
1416
|
-
for (k in h0) if (!(k in h1)) return false;
|
1417
|
-
for (k in h1) if (!(k in h0)) return false;
|
1418
|
-
return true;
|
1419
|
-
};
|
1420
|
-
|
1421
|
-
CSSOCompressor.prototype.getHash = function(tokens) {
|
1422
|
-
var r = {};
|
1423
|
-
for (var i = 0; i < tokens.length; i++) r[tokens[i][0].s] = 1;
|
1424
|
-
return r;
|
1425
|
-
};
|
1426
|
-
|
1427
|
-
CSSOCompressor.prototype.hashInHash = function(h0, h1) {
|
1428
|
-
for (var k in h0) if (!(k in h1)) return false;
|
1429
|
-
return true;
|
1430
|
-
};
|
1431
|
-
|
1432
|
-
CSSOCompressor.prototype.delimSelectors = function(token) {
|
1433
|
-
for (var i = token.length - 1; i > 2; i--) {
|
1434
|
-
token.splice(i, 0, [{}, 'delim']);
|
1435
|
-
}
|
1436
|
-
};
|
1437
|
-
|
1438
|
-
CSSOCompressor.prototype.delimBlocks = function(token) {
|
1439
|
-
for (var i = token.length - 1; i > 2; i--) {
|
1440
|
-
token.splice(i, 0, [{}, 'decldelim']);
|
1441
|
-
}
|
1442
|
-
};
|
1443
|
-
|
1444
|
-
CSSOCompressor.prototype.copyArray = function(a) {
|
1445
|
-
var r = [], t;
|
1446
|
-
|
1447
|
-
for (var i = 0; i < a.length; i++) {
|
1448
|
-
t = a[i];
|
1449
|
-
if (Array.isArray(t)) r.push(this.copyArray(t));
|
1450
|
-
else if (typeof t === 'object') r.push(this.copyObject(t));
|
1451
|
-
else r.push(t);
|
1452
|
-
}
|
1453
|
-
|
1454
|
-
return r;
|
1455
|
-
};
|
1456
|
-
|
1457
|
-
CSSOCompressor.prototype.copyObject = function(o) {
|
1458
|
-
var r = {};
|
1459
|
-
for (var k in o) r[k] = o[k];
|
1460
|
-
return r;
|
1461
|
-
};
|
1462
|
-
|
1463
|
-
CSSOCompressor.prototype.pathUp = function(path) {
|
1464
|
-
return path.substr(0, path.lastIndexOf('/'));
|
1465
|
-
};
|
1466
|
-
var translator = require('./translator.js').translator(),
|
1467
|
-
cleanInfo = require('./util.js').cleanInfo;
|
1468
|
-
|
1469
|
-
exports.compress = function(tree, ro) {
|
1470
|
-
return new CSSOCompressor().compress(tree, ro);
|
1471
|
-
};
|