csso-rails 0.2.0 → 0.3.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/.gitignore CHANGED
@@ -1,10 +1,10 @@
1
+ .DS_Store
2
+ *~
3
+
4
+ pkg/
5
+ .yardoc/
6
+
1
7
  .rvmrc
2
- *.gem
3
8
  .bundle
4
- *.rbc
5
- .yardoc
6
- Gemfile.lock
7
9
  tmp
8
- .DS_Store
9
- csso/
10
-
10
+ /csso/
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ csso-rails (0.3.0)
5
+ execjs (~> 1.4)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ execjs (1.4.0)
11
+ multi_json (~> 1.0)
12
+ minitest (5.0.3)
13
+ multi_json (1.7.6)
14
+ rake (10.0.4)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ csso-rails!
21
+ minitest
22
+ rake
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  Ruby adapter for [github.com/css/csso](https://github.com/css/csso).
4
4
 
5
- ## About
6
5
  CSSO does structure-optimization for CSS.
7
6
  CSS is usually reduced more than in half in uncompressed and around 15% in gzipped.
8
7
 
@@ -28,11 +27,16 @@ Please note than benchmark was taken in summer of 2012, since then things may ha
28
27
  ## Usage
29
28
 
30
29
  ### In Rails 3.1+
31
- add `gem 'csso-rails'` to your gemfile, and that’s it!
30
+
31
+ Add `gem 'csso-rails'` to your gemfile, and that’s it!
32
32
  (also you may want to add some javascript runtime for ExecJS to pick up, like `gem 'therubyracer'`)
33
33
 
34
34
  Upon including it becomes the default compressor even if sass is included too.
35
- More explicit way – set in config: `config.assets.css_compressor = :csso`.
35
+ More explicit way – set in `config/environment/production.rb`:
36
+
37
+ ```ruby
38
+ config.assets.css_compressor = :csso
39
+ ```
36
40
 
37
41
  ### Sprockets
38
42
 
@@ -40,8 +44,7 @@ If you use Sprockets without Rails:
40
44
 
41
45
  ```ruby
42
46
  require 'csso'
43
- Csso::CssCompressor.register!
44
- sprockets_env.css_compressor = :csso
47
+ Csso.install(sprockets_env)
45
48
  ```
46
49
 
47
50
  ### In Plain Ruby
@@ -51,7 +54,7 @@ require 'csso'
51
54
  puts Csso.optimize("a{ color: #FF0000; }") # produces "a{color:red}"
52
55
  ```
53
56
 
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).
57
+ 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).
55
58
 
56
59
  ### In Command Line
57
60
 
data/lib/csso-rails.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  require 'csso'
2
- require 'csso/rails' if defined?(Rails)
2
+ require 'csso/railtie' if defined?(Rails)
data/lib/csso.rb CHANGED
@@ -1,13 +1,20 @@
1
1
  require 'csso/version'
2
- require 'csso/js_lib'
3
- require 'csso/compressor'
4
2
 
5
3
  module Csso
6
-
7
- @csso = Csso::JsLib.new
4
+ autoload :JsLib, 'csso/js_lib'
5
+ autoload :Compressor, 'csso/compressor'
8
6
 
9
7
  def self.js_api
10
- @csso
8
+ @csso ||= Csso::JsLib.new
9
+ end
10
+
11
+ def self.install(sprockets)
12
+ if sprockets.respond_to? :register_compressor
13
+ sprockets.register_compressor('text/css', :csso, Compressor.new)
14
+ sprockets.css_compressor = :csso
15
+ else
16
+ Sprockets::Compressors.register_css_compressor(:csso, 'Csso::Compressor', :default => true)
17
+ end
11
18
  end
12
19
 
13
20
  def self.optimize(css, maniac_mode=false, structural_optimization=true)
@@ -0,0 +1,9 @@
1
+ module Csso
2
+ class Compressor
3
+ def compress(css)
4
+ require 'csso'
5
+ #TODO: settings?
6
+ Csso.optimize(css, true)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ <%
2
+ # template for single-file csso lib
3
+
4
+ def file(filename)
5
+ File.read(filename).strip
6
+ end
7
+
8
+ %>/*
9
+ <%= " THIS FILE IS AUTOGENERATED! DO NOT EDIT!\n See #{__FILE__} instead." %>
10
+
11
+ Based on <%= file 'csso/VERSION' %> revision <%= file 'csso/.git/refs/heads/master' %>
12
+ */
13
+
14
+ console = {
15
+ log: function(){},
16
+ error: function(txt){
17
+ throw txt;
18
+ }
19
+ };
20
+
21
+ <%= file 'csso/web/csso.web.js' %>
22
+
23
+ do_compression = function(css, disable_structural){
24
+ var compressor = new CSSOCompressor(), translator = new CSSOTranslator();
25
+ return translator.translate(
26
+ cleanInfo(
27
+ compressor.compress(
28
+ srcToCSSP(css, 'stylesheet', true),
29
+ disable_structural
30
+ )
31
+ )
32
+ );
33
+ };
@@ -0,0 +1,22 @@
1
+ require 'execjs'
2
+
3
+ module Csso
4
+ class JsLib
5
+
6
+ def initialize
7
+ if ExecJS.runtime.is_a?(ExecJS::ExternalRuntime)
8
+ warn "You're using ExecJS::ExternalRuntime, did you forget to add therubyracer or other execjs runtime to gemfile?"
9
+ end
10
+
11
+ lib = File.read(File.expand_path('../../' + CSSO_JS_LIB, File.dirname(__FILE__)))
12
+ unless @csso = ExecJS.runtime.compile(lib)
13
+ raise 'cannot compile or what?'
14
+ end
15
+ end
16
+
17
+ def compress css, structural_optimization=true
18
+ @csso.call("do_compression", css, !structural_optimization)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require "action_controller/railtie"
2
+
3
+ module Csso
4
+
5
+ class Railtie < ::Rails::Railtie
6
+ initializer "csso.environment", :after => "sprockets.environment" do |app|
7
+ Csso.install(app.assets)
8
+ end
9
+
10
+ # saas-rails-3.2.4(and may be others) sets itself as default, ignoring config? => override :(
11
+ initializer "csso.setup", :after => :setup_compression, :group => :all do |app|
12
+ if app.config.assets.enabled
13
+ app.config.assets.css_compressor = :csso
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,4 @@
1
+ module Csso
2
+ VERSION = '0.3.0'
3
+ CSSO_JS_LIB = 'vendor/csso/csso.js'
4
+ end
@@ -0,0 +1,35 @@
1
+ require 'minitest/autorun'
2
+ require 'csso'
3
+
4
+ describe Csso do
5
+
6
+ subject { Csso }
7
+
8
+ it "dummy test" do
9
+ 1.must_equal 1
10
+ end
11
+
12
+ it "should optimize css" do
13
+ subject.optimize("a {\ncolor: white; }").must_equal "a{color:#fff}"
14
+ end
15
+
16
+ it "should optimize structure" do
17
+ subject.optimize("a {\ncolor: white; } a{color: red;}").must_equal "a{color:red}"
18
+ end
19
+
20
+ it "should optimize structure" do
21
+ skip "original csso is a bit broken at the moment"
22
+ # FIXME: csso produces "a{color:#fff;color:red}" on this :(
23
+ subject.optimize("a {\ncolor: white; } a{color: #ff0000;}").must_equal "a{color:red}"
24
+ end
25
+
26
+ it "should optimize structure in maniac mode" do
27
+ subject.optimize("a {\ncolor: white; } a{color: #ff0000;}", true).must_equal "a{color:red}"
28
+ end
29
+
30
+ it 'should produce no error on empty input' do
31
+ subject.optimize(nil).must_be_nil
32
+ subject.optimize("").must_equal ""
33
+ end
34
+
35
+ end
@@ -0,0 +1,3915 @@
1
+ /*
2
+ THIS FILE IS AUTOGENERATED! DO NOT EDIT!
3
+ See lib/csso/csso.js.erb instead.
4
+
5
+ Based on CSSO 1.3.7 revision 115eabd536a6224b08a59a57c64e2fdecb0f1350
6
+ */
7
+
8
+ console = {
9
+ log: function(){},
10
+ error: function(txt){
11
+ throw txt;
12
+ }
13
+ };
14
+
15
+ var $util = {};
16
+
17
+ $util.cleanInfo = function(tree) {
18
+ var r = [];
19
+ tree = tree.slice(1);
20
+
21
+ tree.forEach(function(e) {
22
+ r.push(Array.isArray(e) ? $util.cleanInfo(e) : e);
23
+ });
24
+
25
+ return r;
26
+ };
27
+
28
+ $util.treeToString = function(tree, level) {
29
+ var spaces = $util.dummySpaces(level),
30
+ level = level ? level : 0,
31
+ s = (level ? '\n' + spaces : '') + '[';
32
+
33
+ tree.forEach(function(e) {
34
+ s += (Array.isArray(e) ? $util.treeToString(e, level + 1) : e.f !== undefined ? $util.ircToString(e) : ('\'' + e.toString() + '\'')) + ', ';
35
+ });
36
+
37
+ return s.substr(0, s.length - 2) + ']';
38
+ };
39
+
40
+ $util.ircToString = function(o) {
41
+ return '{' + o.f + ',' + o.l + '}';
42
+ };
43
+
44
+ $util.dummySpaces = function(num) {
45
+ return ' '.substr(0, num * 2);
46
+ };
47
+ function srcToCSSP(s, rule, _needInfo) {
48
+ var TokenType = {
49
+ StringSQ: 'StringSQ',
50
+ StringDQ: 'StringDQ',
51
+ CommentML: 'CommentML',
52
+ CommentSL: 'CommentSL',
53
+
54
+ Newline: 'Newline',
55
+ Space: 'Space',
56
+ Tab: 'Tab',
57
+
58
+ ExclamationMark: 'ExclamationMark', // !
59
+ QuotationMark: 'QuotationMark', // "
60
+ NumberSign: 'NumberSign', // #
61
+ DollarSign: 'DollarSign', // $
62
+ PercentSign: 'PercentSign', // %
63
+ Ampersand: 'Ampersand', // &
64
+ Apostrophe: 'Apostrophe', // '
65
+ LeftParenthesis: 'LeftParenthesis', // (
66
+ RightParenthesis: 'RightParenthesis', // )
67
+ Asterisk: 'Asterisk', // *
68
+ PlusSign: 'PlusSign', // +
69
+ Comma: 'Comma', // ,
70
+ HyphenMinus: 'HyphenMinus', // -
71
+ FullStop: 'FullStop', // .
72
+ Solidus: 'Solidus', // /
73
+ Colon: 'Colon', // :
74
+ Semicolon: 'Semicolon', // ;
75
+ LessThanSign: 'LessThanSign', // <
76
+ EqualsSign: 'EqualsSign', // =
77
+ GreaterThanSign: 'GreaterThanSign', // >
78
+ QuestionMark: 'QuestionMark', // ?
79
+ CommercialAt: 'CommercialAt', // @
80
+ LeftSquareBracket: 'LeftSquareBracket', // [
81
+ ReverseSolidus: 'ReverseSolidus', // \
82
+ RightSquareBracket: 'RightSquareBracket', // ]
83
+ CircumflexAccent: 'CircumflexAccent', // ^
84
+ LowLine: 'LowLine', // _
85
+ LeftCurlyBracket: 'LeftCurlyBracket', // {
86
+ VerticalLine: 'VerticalLine', // |
87
+ RightCurlyBracket: 'RightCurlyBracket', // }
88
+ Tilde: 'Tilde', // ~
89
+
90
+ Identifier: 'Identifier',
91
+ DecimalNumber: 'DecimalNumber'
92
+ };
93
+
94
+ function getTokens(s) {
95
+ var Punctuation,
96
+ urlMode = false,
97
+ blockMode = 0;
98
+
99
+ Punctuation = {
100
+ ' ': TokenType.Space,
101
+ '\n': TokenType.Newline,
102
+ '\r': TokenType.Newline,
103
+ '\t': TokenType.Tab,
104
+ '!': TokenType.ExclamationMark,
105
+ '"': TokenType.QuotationMark,
106
+ '#': TokenType.NumberSign,
107
+ '$': TokenType.DollarSign,
108
+ '%': TokenType.PercentSign,
109
+ '&': TokenType.Ampersand,
110
+ '\'': TokenType.Apostrophe,
111
+ '(': TokenType.LeftParenthesis,
112
+ ')': TokenType.RightParenthesis,
113
+ '*': TokenType.Asterisk,
114
+ '+': TokenType.PlusSign,
115
+ ',': TokenType.Comma,
116
+ '-': TokenType.HyphenMinus,
117
+ '.': TokenType.FullStop,
118
+ '/': TokenType.Solidus,
119
+ ':': TokenType.Colon,
120
+ ';': TokenType.Semicolon,
121
+ '<': TokenType.LessThanSign,
122
+ '=': TokenType.EqualsSign,
123
+ '>': TokenType.GreaterThanSign,
124
+ '?': TokenType.QuestionMark,
125
+ '@': TokenType.CommercialAt,
126
+ '[': TokenType.LeftSquareBracket,
127
+ // '\\': TokenType.ReverseSolidus,
128
+ ']': TokenType.RightSquareBracket,
129
+ '^': TokenType.CircumflexAccent,
130
+ '_': TokenType.LowLine,
131
+ '{': TokenType.LeftCurlyBracket,
132
+ '|': TokenType.VerticalLine,
133
+ '}': TokenType.RightCurlyBracket,
134
+ '~': TokenType.Tilde
135
+ };
136
+
137
+ function isDecimalDigit(c) {
138
+ return '0123456789'.indexOf(c) >= 0;
139
+ }
140
+
141
+ function throwError(message) {
142
+ throw message;
143
+ }
144
+
145
+ var buffer = '',
146
+ tokens = [],
147
+ pos,
148
+ tn = 0,
149
+ ln = 1;
150
+
151
+ function _getTokens(s) {
152
+ if (!s) return [];
153
+
154
+ tokens = [];
155
+
156
+ var c, cn;
157
+
158
+ for (pos = 0; pos < s.length; pos++) {
159
+ c = s.charAt(pos);
160
+ cn = s.charAt(pos + 1);
161
+
162
+ if (c === '/' && cn === '*') {
163
+ parseMLComment(s);
164
+ } else if (!urlMode && c === '/' && cn === '/') {
165
+ if (blockMode > 0) parseIdentifier(s);
166
+ else parseSLComment(s);
167
+ } else if (c === '"' || c === "'") {
168
+ parseString(s, c);
169
+ } else if (c === ' ') {
170
+ parseSpaces(s)
171
+ } else if (c in Punctuation) {
172
+ pushToken(Punctuation[c], c);
173
+ if (c === '\n' || c === '\r') ln++;
174
+ if (c === ')') urlMode = false;
175
+ if (c === '{') blockMode++;
176
+ if (c === '}') blockMode--;
177
+ } else if (isDecimalDigit(c)) {
178
+ parseDecimalNumber(s);
179
+ } else {
180
+ parseIdentifier(s);
181
+ }
182
+ }
183
+
184
+ mark();
185
+
186
+ return tokens;
187
+ }
188
+
189
+ function pushToken(type, value) {
190
+ tokens.push({ tn: tn++, ln: ln, type: type, value: value });
191
+ }
192
+
193
+ function parseSpaces(s) {
194
+ var start = pos;
195
+
196
+ for (; pos < s.length; pos++) {
197
+ if (s.charAt(pos) !== ' ') break;
198
+ }
199
+
200
+ pushToken(TokenType.Space, s.substring(start, pos));
201
+ pos--;
202
+ }
203
+
204
+ function parseMLComment(s) {
205
+ var start = pos;
206
+
207
+ for (pos = pos + 2; pos < s.length; pos++) {
208
+ if (s.charAt(pos) === '*') {
209
+ if (s.charAt(pos + 1) === '/') {
210
+ pos++;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+
216
+ pushToken(TokenType.CommentML, s.substring(start, pos + 1));
217
+ }
218
+
219
+ function parseSLComment(s) {
220
+ var start = pos;
221
+
222
+ for (pos = pos + 2; pos < s.length; pos++) {
223
+ if (s.charAt(pos) === '\n' || s.charAt(pos) === '\r') {
224
+ pos++;
225
+ break;
226
+ }
227
+ }
228
+
229
+ pushToken(TokenType.CommentSL, s.substring(start, pos));
230
+ pos--;
231
+ }
232
+
233
+ function parseString(s, q) {
234
+ var start = pos;
235
+
236
+ for (pos = pos + 1; pos < s.length; pos++) {
237
+ if (s.charAt(pos) === '\\') pos++;
238
+ else if (s.charAt(pos) === q) break;
239
+ }
240
+
241
+ pushToken(q === '"' ? TokenType.StringDQ : TokenType.StringSQ, s.substring(start, pos + 1));
242
+ }
243
+
244
+ function parseDecimalNumber(s) {
245
+ var start = pos;
246
+
247
+ for (; pos < s.length; pos++) {
248
+ if (!isDecimalDigit(s.charAt(pos))) break;
249
+ }
250
+
251
+ pushToken(TokenType.DecimalNumber, s.substring(start, pos));
252
+ pos--;
253
+ }
254
+
255
+ function parseIdentifier(s) {
256
+ var start = pos;
257
+
258
+ while (s.charAt(pos) === '/') pos++;
259
+
260
+ for (; pos < s.length; pos++) {
261
+ if (s.charAt(pos) === '\\') pos++;
262
+ else if (s.charAt(pos) in Punctuation) break;
263
+ }
264
+
265
+ var ident = s.substring(start, pos);
266
+
267
+ urlMode = urlMode || ident === 'url';
268
+
269
+ pushToken(TokenType.Identifier, ident);
270
+ pos--;
271
+ }
272
+
273
+ // ====================================
274
+ // second run
275
+ // ====================================
276
+
277
+ function mark() {
278
+ var ps = [], // Parenthesis
279
+ sbs = [], // SquareBracket
280
+ cbs = [], // CurlyBracket
281
+ t;
282
+
283
+ for (var i = 0; i < tokens.length; i++) {
284
+ t = tokens[i];
285
+ switch(t.type) {
286
+ case TokenType.LeftParenthesis:
287
+ ps.push(i);
288
+ break;
289
+ case TokenType.RightParenthesis:
290
+ if (ps.length) {
291
+ t.left = ps.pop();
292
+ tokens[t.left].right = i;
293
+ }
294
+ break;
295
+ case TokenType.LeftSquareBracket:
296
+ sbs.push(i);
297
+ break;
298
+ case TokenType.RightSquareBracket:
299
+ if (sbs.length) {
300
+ t.left = sbs.pop();
301
+ tokens[t.left].right = i;
302
+ }
303
+ break;
304
+ case TokenType.LeftCurlyBracket:
305
+ cbs.push(i);
306
+ break;
307
+ case TokenType.RightCurlyBracket:
308
+ if (cbs.length) {
309
+ t.left = cbs.pop();
310
+ tokens[t.left].right = i;
311
+ }
312
+ break;
313
+ }
314
+ }
315
+ }
316
+
317
+ return _getTokens(s);
318
+ }
319
+ // version: 1.0.0
320
+
321
+ function getCSSPAST(_tokens, rule, _needInfo) {
322
+
323
+ var tokens,
324
+ pos,
325
+ failLN = 0,
326
+ currentBlockLN = 0,
327
+ needInfo = false;
328
+
329
+ var CSSPNodeType,
330
+ CSSLevel,
331
+ CSSPRules;
332
+
333
+ CSSPNodeType = {
334
+ IdentType: 'ident',
335
+ AtkeywordType: 'atkeyword',
336
+ StringType: 'string',
337
+ ShashType: 'shash',
338
+ VhashType: 'vhash',
339
+ NumberType: 'number',
340
+ PercentageType: 'percentage',
341
+ DimensionType: 'dimension',
342
+ CdoType: 'cdo',
343
+ CdcType: 'cdc',
344
+ DecldelimType: 'decldelim',
345
+ SType: 's',
346
+ AttrselectorType: 'attrselector',
347
+ AttribType: 'attrib',
348
+ NthType: 'nth',
349
+ NthselectorType: 'nthselector',
350
+ NamespaceType: 'namespace',
351
+ ClazzType: 'clazz',
352
+ PseudoeType: 'pseudoe',
353
+ PseudocType: 'pseudoc',
354
+ DelimType: 'delim',
355
+ StylesheetType: 'stylesheet',
356
+ AtrulebType: 'atruleb',
357
+ AtrulesType: 'atrules',
358
+ AtrulerqType: 'atrulerq',
359
+ AtrulersType: 'atrulers',
360
+ AtrulerType: 'atruler',
361
+ BlockType: 'block',
362
+ RulesetType: 'ruleset',
363
+ CombinatorType: 'combinator',
364
+ SimpleselectorType: 'simpleselector',
365
+ SelectorType: 'selector',
366
+ DeclarationType: 'declaration',
367
+ PropertyType: 'property',
368
+ ImportantType: 'important',
369
+ UnaryType: 'unary',
370
+ OperatorType: 'operator',
371
+ BracesType: 'braces',
372
+ ValueType: 'value',
373
+ ProgidType: 'progid',
374
+ FiltervType: 'filterv',
375
+ FilterType: 'filter',
376
+ CommentType: 'comment',
377
+ UriType: 'uri',
378
+ RawType: 'raw',
379
+ FunctionBodyType: 'functionBody',
380
+ FunktionType: 'funktion',
381
+ FunctionExpressionType: 'functionExpression',
382
+ UnknownType: 'unknown'
383
+ };
384
+
385
+ CSSPRules = {
386
+ 'ident': function() { if (checkIdent(pos)) return getIdent() },
387
+ 'atkeyword': function() { if (checkAtkeyword(pos)) return getAtkeyword() },
388
+ 'string': function() { if (checkString(pos)) return getString() },
389
+ 'shash': function() { if (checkShash(pos)) return getShash() },
390
+ 'vhash': function() { if (checkVhash(pos)) return getVhash() },
391
+ 'number': function() { if (checkNumber(pos)) return getNumber() },
392
+ 'percentage': function() { if (checkPercentage(pos)) return getPercentage() },
393
+ 'dimension': function() { if (checkDimension(pos)) return getDimension() },
394
+ // 'cdo': function() { if (checkCDO()) return getCDO() },
395
+ // 'cdc': function() { if (checkCDC()) return getCDC() },
396
+ 'decldelim': function() { if (checkDecldelim(pos)) return getDecldelim() },
397
+ 's': function() { if (checkS(pos)) return getS() },
398
+ 'attrselector': function() { if (checkAttrselector(pos)) return getAttrselector() },
399
+ 'attrib': function() { if (checkAttrib(pos)) return getAttrib() },
400
+ 'nth': function() { if (checkNth(pos)) return getNth() },
401
+ 'nthselector': function() { if (checkNthselector(pos)) return getNthselector() },
402
+ 'namespace': function() { if (checkNamespace(pos)) return getNamespace() },
403
+ 'clazz': function() { if (checkClazz(pos)) return getClazz() },
404
+ 'pseudoe': function() { if (checkPseudoe(pos)) return getPseudoe() },
405
+ 'pseudoc': function() { if (checkPseudoc(pos)) return getPseudoc() },
406
+ 'delim': function() { if (checkDelim(pos)) return getDelim() },
407
+ 'stylesheet': function() { if (checkStylesheet(pos)) return getStylesheet() },
408
+ 'atruleb': function() { if (checkAtruleb(pos)) return getAtruleb() },
409
+ 'atrules': function() { if (checkAtrules(pos)) return getAtrules() },
410
+ 'atrulerq': function() { if (checkAtrulerq(pos)) return getAtrulerq() },
411
+ 'atrulers': function() { if (checkAtrulers(pos)) return getAtrulers() },
412
+ 'atruler': function() { if (checkAtruler(pos)) return getAtruler() },
413
+ 'block': function() { if (checkBlock(pos)) return getBlock() },
414
+ 'ruleset': function() { if (checkRuleset(pos)) return getRuleset() },
415
+ 'combinator': function() { if (checkCombinator(pos)) return getCombinator() },
416
+ 'simpleselector': function() { if (checkSimpleselector(pos)) return getSimpleSelector() },
417
+ 'selector': function() { if (checkSelector(pos)) return getSelector() },
418
+ 'declaration': function() { if (checkDeclaration(pos)) return getDeclaration() },
419
+ 'property': function() { if (checkProperty(pos)) return getProperty() },
420
+ 'important': function() { if (checkImportant(pos)) return getImportant() },
421
+ 'unary': function() { if (checkUnary(pos)) return getUnary() },
422
+ 'operator': function() { if (checkOperator(pos)) return getOperator() },
423
+ 'braces': function() { if (checkBraces(pos)) return getBraces() },
424
+ 'value': function() { if (checkValue(pos)) return getValue() },
425
+ 'progid': function() { if (checkProgid(pos)) return getProgid() },
426
+ 'filterv': function() { if (checkFilterv(pos)) return getFilterv() },
427
+ 'filter': function() { if (checkFilter(pos)) return getFilter() },
428
+ 'comment': function() { if (checkComment(pos)) return getComment() },
429
+ 'uri': function() { if (checkUri(pos)) return getUri() },
430
+ 'raw': function() { if (checkRaw(pos)) return getRaw() },
431
+ 'funktion': function() { if (checkFunktion(pos)) return getFunktion() },
432
+ 'functionExpression': function() { if (checkFunctionExpression(pos)) return getFunctionExpression() },
433
+ 'unknown': function() { if (checkUnknown(pos)) return getUnknown() }
434
+ };
435
+
436
+ function fail(token) {
437
+ if (token && token.ln > failLN) failLN = token.ln;
438
+ }
439
+
440
+ function throwError() {
441
+ console.error('Please check the validity of the CSS block starting from the line #' + currentBlockLN);
442
+ if (process) process.exit(1);
443
+ throw new Error();
444
+ }
445
+
446
+ function _getAST(_tokens, rule, _needInfo) {
447
+ tokens = _tokens;
448
+ needInfo = _needInfo;
449
+ pos = 0;
450
+
451
+ markSC();
452
+
453
+ return rule ? CSSPRules[rule]() : CSSPRules['stylesheet']();
454
+ }
455
+
456
+ //any = braces | string | percentage | dimension | number | uri | functionExpression | funktion | ident | unary
457
+ function checkAny(_i) {
458
+ return checkBraces(_i) ||
459
+ checkString(_i) ||
460
+ checkPercentage(_i) ||
461
+ checkDimension(_i) ||
462
+ checkNumber(_i) ||
463
+ checkUri(_i) ||
464
+ checkFunctionExpression(_i) ||
465
+ checkFunktion(_i) ||
466
+ checkIdent(_i) ||
467
+ checkUnary(_i);
468
+ }
469
+
470
+ function getAny() {
471
+ if (checkBraces(pos)) return getBraces();
472
+ else if (checkString(pos)) return getString();
473
+ else if (checkPercentage(pos)) return getPercentage();
474
+ else if (checkDimension(pos)) return getDimension();
475
+ else if (checkNumber(pos)) return getNumber();
476
+ else if (checkUri(pos)) return getUri();
477
+ else if (checkFunctionExpression(pos)) return getFunctionExpression();
478
+ else if (checkFunktion(pos)) return getFunktion();
479
+ else if (checkIdent(pos)) return getIdent();
480
+ else if (checkUnary(pos)) return getUnary();
481
+ }
482
+
483
+ //atkeyword = '@' ident:x -> [#atkeyword, x]
484
+ function checkAtkeyword(_i) {
485
+ var l;
486
+
487
+ if (tokens[_i++].type !== TokenType.CommercialAt) return fail(tokens[_i - 1]);
488
+
489
+ if (l = checkIdent(_i)) return l + 1;
490
+
491
+ return fail(tokens[_i]);
492
+ }
493
+
494
+ function getAtkeyword() {
495
+ var startPos = pos;
496
+
497
+ pos++;
498
+
499
+ return needInfo?
500
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.AtkeywordType, getIdent()]:
501
+ [CSSPNodeType.AtkeywordType, getIdent()];
502
+ }
503
+
504
+ //attrib = '[' sc*:s0 ident:x sc*:s1 attrselector:a sc*:s2 (ident | string):y sc*:s3 ']' -> this.concat([#attrib], s0, [x], s1, [a], s2, [y], s3)
505
+ // | '[' sc*:s0 ident:x sc*:s1 ']' -> this.concat([#attrib], s0, [x], s1),
506
+ function checkAttrib(_i) {
507
+ if (tokens[_i].type !== TokenType.LeftSquareBracket) return fail(tokens[_i]);
508
+
509
+ if (!tokens[_i].right) return fail(tokens[_i]);
510
+
511
+ return tokens[_i].right - _i + 1;
512
+ }
513
+
514
+ function checkAttrib1(_i) {
515
+ var start = _i;
516
+
517
+ _i++;
518
+
519
+ var l = checkSC(_i); // s0
520
+
521
+ if (l) _i += l;
522
+
523
+ if (l = checkIdent(_i)) _i += l; // x
524
+ else return fail(tokens[_i]);
525
+
526
+ if (l = checkSC(_i)) _i += l; // s1
527
+
528
+ if (l = checkAttrselector(_i)) _i += l; // a
529
+ else return fail(tokens[_i]);
530
+
531
+ if (l = checkSC(_i)) _i += l; // s2
532
+
533
+ if ((l = checkIdent(_i)) || (l = checkString(_i))) _i += l; // y
534
+ else return fail(tokens[_i]);
535
+
536
+ if (l = checkSC(_i)) _i += l; // s3
537
+
538
+ if (tokens[_i].type === TokenType.RightSquareBracket) return _i - start;
539
+
540
+ return fail(tokens[_i]);
541
+ }
542
+
543
+ function getAttrib1() {
544
+ var startPos = pos;
545
+
546
+ pos++;
547
+
548
+ var a = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.AttribType] : [CSSPNodeType.AttribType])
549
+ .concat(getSC())
550
+ .concat([getIdent()])
551
+ .concat(getSC())
552
+ .concat([getAttrselector()])
553
+ .concat(getSC())
554
+ .concat([checkString(pos)? getString() : getIdent()])
555
+ .concat(getSC());
556
+
557
+ pos++;
558
+
559
+ return a;
560
+ }
561
+
562
+ function checkAttrib2(_i) {
563
+ var start = _i;
564
+
565
+ _i++;
566
+
567
+ var l = checkSC(_i);
568
+
569
+ if (l) _i += l;
570
+
571
+ if (l = checkIdent(_i)) _i += l;
572
+
573
+ if (l = checkSC(_i)) _i += l;
574
+
575
+ if (tokens[_i].type === TokenType.RightSquareBracket) return _i - start;
576
+
577
+ return fail(tokens[_i]);
578
+ }
579
+
580
+ function getAttrib2() {
581
+ var startPos = pos;
582
+
583
+ pos++;
584
+
585
+ var a = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.AttribType] : [CSSPNodeType.AttribType])
586
+ .concat(getSC())
587
+ .concat([getIdent()])
588
+ .concat(getSC());
589
+
590
+ pos++;
591
+
592
+ return a;
593
+ }
594
+
595
+ function getAttrib() {
596
+ if (checkAttrib1(pos)) return getAttrib1();
597
+ if (checkAttrib2(pos)) return getAttrib2();
598
+ }
599
+
600
+ //attrselector = (seq('=') | seq('~=') | seq('^=') | seq('$=') | seq('*=') | seq('|=')):x -> [#attrselector, x]
601
+ function checkAttrselector(_i) {
602
+ if (tokens[_i].type === TokenType.EqualsSign) return 1;
603
+ if (tokens[_i].type === TokenType.VerticalLine && (!tokens[_i + 1] || tokens[_i + 1].type !== TokenType.EqualsSign)) return 1;
604
+
605
+ if (!tokens[_i + 1] || tokens[_i + 1].type !== TokenType.EqualsSign) return fail(tokens[_i]);
606
+
607
+ switch(tokens[_i].type) {
608
+ case TokenType.Tilde:
609
+ case TokenType.CircumflexAccent:
610
+ case TokenType.DollarSign:
611
+ case TokenType.Asterisk:
612
+ case TokenType.VerticalLine:
613
+ return 2;
614
+ }
615
+
616
+ return fail(tokens[_i]);
617
+ }
618
+
619
+ function getAttrselector() {
620
+ var startPos = pos,
621
+ s = tokens[pos++].value;
622
+
623
+ if (tokens[pos] && tokens[pos].type === TokenType.EqualsSign) s += tokens[pos++].value;
624
+
625
+ return needInfo?
626
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.AttrselectorType, s] :
627
+ [CSSPNodeType.AttrselectorType, s];
628
+ }
629
+
630
+ //atrule = atruler | atruleb | atrules
631
+ function checkAtrule(_i) {
632
+ var start = _i,
633
+ l;
634
+
635
+ if (tokens[start].atrule_l !== undefined) return tokens[start].atrule_l;
636
+
637
+ if (l = checkAtruler(_i)) tokens[_i].atrule_type = 1;
638
+ else if (l = checkAtruleb(_i)) tokens[_i].atrule_type = 2;
639
+ else if (l = checkAtrules(_i)) tokens[_i].atrule_type = 3;
640
+ else return fail(tokens[start]);
641
+
642
+ tokens[start].atrule_l = l;
643
+
644
+ return l;
645
+ }
646
+
647
+ function getAtrule() {
648
+ switch (tokens[pos].atrule_type) {
649
+ case 1: return getAtruler();
650
+ case 2: return getAtruleb();
651
+ case 3: return getAtrules();
652
+ }
653
+ }
654
+
655
+ //atruleb = atkeyword:ak tset*:ap block:b -> this.concat([#atruleb, ak], ap, [b])
656
+ function checkAtruleb(_i) {
657
+ var start = _i,
658
+ l;
659
+
660
+ if (l = checkAtkeyword(_i)) _i += l;
661
+ else return fail(tokens[_i]);
662
+
663
+ if (l = checkTsets(_i)) _i += l;
664
+
665
+ if (l = checkBlock(_i)) _i += l;
666
+ else return fail(tokens[_i]);
667
+
668
+ return _i - start;
669
+ }
670
+
671
+ function getAtruleb() {
672
+ return (needInfo?
673
+ [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulebType, getAtkeyword()] :
674
+ [CSSPNodeType.AtrulebType, getAtkeyword()])
675
+ .concat(getTsets())
676
+ .concat([getBlock()]);
677
+ }
678
+
679
+ //atruler = atkeyword:ak atrulerq:x '{' atrulers:y '}' -> [#atruler, ak, x, y]
680
+ function checkAtruler(_i) {
681
+ var start = _i,
682
+ l;
683
+
684
+ if (l = checkAtkeyword(_i)) _i += l;
685
+ else return fail(tokens[_i]);
686
+
687
+ if (l = checkAtrulerq(_i)) _i += l;
688
+
689
+ if (_i < tokens.length && tokens[_i].type === TokenType.LeftCurlyBracket) _i++;
690
+ else return fail(tokens[_i]);
691
+
692
+ if (l = checkAtrulers(_i)) _i += l;
693
+
694
+ if (_i < tokens.length && tokens[_i].type === TokenType.RightCurlyBracket) _i++;
695
+ else return fail(tokens[_i]);
696
+
697
+ return _i - start;
698
+ }
699
+
700
+ function getAtruler() {
701
+ var atruler = needInfo?
702
+ [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulerType, getAtkeyword(), getAtrulerq()] :
703
+ [CSSPNodeType.AtrulerType, getAtkeyword(), getAtrulerq()];
704
+
705
+ pos++;
706
+
707
+ atruler.push(getAtrulers());
708
+
709
+ pos++;
710
+
711
+ return atruler;
712
+ }
713
+
714
+ //atrulerq = tset*:ap -> [#atrulerq].concat(ap)
715
+ function checkAtrulerq(_i) {
716
+ return checkTsets(_i);
717
+ }
718
+
719
+ function getAtrulerq() {
720
+ return (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulerqType] : [CSSPNodeType.AtrulerqType]).concat(getTsets());
721
+ }
722
+
723
+ //atrulers = sc*:s0 ruleset*:r sc*:s1 -> this.concat([#atrulers], s0, r, s1)
724
+ function checkAtrulers(_i) {
725
+ var start = _i,
726
+ l;
727
+
728
+ if (l = checkSC(_i)) _i += l;
729
+
730
+ while ((l = checkRuleset(_i)) || (l = checkAtrule(_i)) || (l = checkSC(_i))) {
731
+ _i += l;
732
+ }
733
+
734
+ tokens[_i].atrulers_end = 1;
735
+
736
+ if (l = checkSC(_i)) _i += l;
737
+
738
+ return _i - start;
739
+ }
740
+
741
+ function getAtrulers() {
742
+ var atrulers = (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulersType] : [CSSPNodeType.AtrulersType]).concat(getSC()),
743
+ x;
744
+
745
+ while (!tokens[pos].atrulers_end) {
746
+ if (checkSC(pos)) {
747
+ atrulers = atrulers.concat(getSC());
748
+ } else if (checkRuleset(pos)) {
749
+ atrulers.push(getRuleset());
750
+ } else {
751
+ atrulers.push(getAtrule());
752
+ }
753
+ }
754
+
755
+ return atrulers.concat(getSC());
756
+ }
757
+
758
+ //atrules = atkeyword:ak tset*:ap ';' -> this.concat([#atrules, ak], ap)
759
+ function checkAtrules(_i) {
760
+ var start = _i,
761
+ l;
762
+
763
+ if (l = checkAtkeyword(_i)) _i += l;
764
+ else return fail(tokens[_i]);
765
+
766
+ if (l = checkTsets(_i)) _i += l;
767
+
768
+ if (_i >= tokens.length) return _i - start;
769
+
770
+ if (tokens[_i].type === TokenType.Semicolon) _i++;
771
+ else return fail(tokens[_i]);
772
+
773
+ return _i - start;
774
+ }
775
+
776
+ function getAtrules() {
777
+ var atrules = (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulesType, getAtkeyword()] : [CSSPNodeType.AtrulesType, getAtkeyword()]).concat(getTsets());
778
+
779
+ pos++;
780
+
781
+ return atrules;
782
+ }
783
+
784
+ //block = '{' blockdecl*:x '}' -> this.concatContent([#block], x)
785
+ function checkBlock(_i) {
786
+ if (_i < tokens.length && tokens[_i].type === TokenType.LeftCurlyBracket) return tokens[_i].right - _i + 1;
787
+
788
+ return fail(tokens[_i]);
789
+ }
790
+
791
+ function getBlock() {
792
+ var block = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.BlockType] : [CSSPNodeType.BlockType],
793
+ end = tokens[pos].right;
794
+
795
+ pos++;
796
+
797
+ while (pos < end) {
798
+ if (checkBlockdecl(pos)) block = block.concat(getBlockdecl());
799
+ else throwError();
800
+ }
801
+
802
+ pos = end + 1;
803
+
804
+ return block;
805
+ }
806
+
807
+ //blockdecl = sc*:s0 (filter | declaration):x decldelim:y sc*:s1 -> this.concat(s0, [x], [y], s1)
808
+ // | sc*:s0 (filter | declaration):x sc*:s1 -> this.concat(s0, [x], s1)
809
+ // | sc*:s0 decldelim:x sc*:s1 -> this.concat(s0, [x], s1)
810
+ // | sc+:s0 -> s0
811
+
812
+ function checkBlockdecl(_i) {
813
+ var l;
814
+
815
+ if (l = _checkBlockdecl0(_i)) tokens[_i].bd_type = 1;
816
+ else if (l = _checkBlockdecl1(_i)) tokens[_i].bd_type = 2;
817
+ else if (l = _checkBlockdecl2(_i)) tokens[_i].bd_type = 3;
818
+ else if (l = _checkBlockdecl3(_i)) tokens[_i].bd_type = 4;
819
+ else return fail(tokens[_i]);
820
+
821
+ return l;
822
+ }
823
+
824
+ function getBlockdecl() {
825
+ switch (tokens[pos].bd_type) {
826
+ case 1: return _getBlockdecl0();
827
+ case 2: return _getBlockdecl1();
828
+ case 3: return _getBlockdecl2();
829
+ case 4: return _getBlockdecl3();
830
+ }
831
+ }
832
+
833
+ //sc*:s0 (filter | declaration):x decldelim:y sc*:s1 -> this.concat(s0, [x], [y], s1)
834
+ function _checkBlockdecl0(_i) {
835
+ var start = _i,
836
+ l;
837
+
838
+ if (l = checkSC(_i)) _i += l;
839
+
840
+ if (l = checkFilter(_i)) {
841
+ tokens[_i].bd_filter = 1;
842
+ _i += l;
843
+ } else if (l = checkDeclaration(_i)) {
844
+ tokens[_i].bd_decl = 1;
845
+ _i += l;
846
+ } else return fail(tokens[_i]);
847
+
848
+ if (_i < tokens.length && (l = checkDecldelim(_i))) _i += l;
849
+ else return fail(tokens[_i]);
850
+
851
+ if (l = checkSC(_i)) _i += l;
852
+
853
+ return _i - start;
854
+ }
855
+
856
+ function _getBlockdecl0() {
857
+ return getSC()
858
+ .concat([tokens[pos].bd_filter? getFilter() : getDeclaration()])
859
+ .concat([getDecldelim()])
860
+ .concat(getSC());
861
+ }
862
+
863
+ //sc*:s0 (filter | declaration):x sc*:s1 -> this.concat(s0, [x], s1)
864
+ function _checkBlockdecl1(_i) {
865
+ var start = _i,
866
+ l;
867
+
868
+ if (l = checkSC(_i)) _i += l;
869
+
870
+ if (l = checkFilter(_i)) {
871
+ tokens[_i].bd_filter = 1;
872
+ _i += l;
873
+ } else if (l = checkDeclaration(_i)) {
874
+ tokens[_i].bd_decl = 1;
875
+ _i += l;
876
+ } else return fail(tokens[_i]);
877
+
878
+ if (l = checkSC(_i)) _i += l;
879
+
880
+ return _i - start;
881
+ }
882
+
883
+ function _getBlockdecl1() {
884
+ return getSC()
885
+ .concat([tokens[pos].bd_filter? getFilter() : getDeclaration()])
886
+ .concat(getSC());
887
+ }
888
+
889
+ //sc*:s0 decldelim:x sc*:s1 -> this.concat(s0, [x], s1)
890
+ function _checkBlockdecl2(_i) {
891
+ var start = _i,
892
+ l;
893
+
894
+ if (l = checkSC(_i)) _i += l;
895
+
896
+ if (l = checkDecldelim(_i)) _i += l;
897
+ else return fail(tokens[_i]);
898
+
899
+ if (l = checkSC(_i)) _i += l;
900
+
901
+ return _i - start;
902
+ }
903
+
904
+ function _getBlockdecl2() {
905
+ return getSC()
906
+ .concat([getDecldelim()])
907
+ .concat(getSC());
908
+ }
909
+
910
+ //sc+:s0 -> s0
911
+ function _checkBlockdecl3(_i) {
912
+ return checkSC(_i);
913
+ }
914
+
915
+ function _getBlockdecl3() {
916
+ return getSC();
917
+ }
918
+
919
+ //braces = '(' tset*:x ')' -> this.concat([#braces, '(', ')'], x)
920
+ // | '[' tset*:x ']' -> this.concat([#braces, '[', ']'], x)
921
+ function checkBraces(_i) {
922
+ if (_i >= tokens.length ||
923
+ (tokens[_i].type !== TokenType.LeftParenthesis &&
924
+ tokens[_i].type !== TokenType.LeftSquareBracket)
925
+ ) return fail(tokens[_i]);
926
+
927
+ return tokens[_i].right - _i + 1;
928
+ }
929
+
930
+ function getBraces() {
931
+ var startPos = pos,
932
+ left = pos,
933
+ right = tokens[pos].right;
934
+
935
+ pos++;
936
+
937
+ var tsets = getTsets();
938
+
939
+ pos++;
940
+
941
+ return needInfo?
942
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.BracesType, tokens[left].value, tokens[right].value].concat(tsets) :
943
+ [CSSPNodeType.BracesType, tokens[left].value, tokens[right].value].concat(tsets);
944
+ }
945
+
946
+ function checkCDC(_i) {}
947
+
948
+ function checkCDO(_i) {}
949
+
950
+ // node: Clazz
951
+ function checkClazz(_i) {
952
+ var l;
953
+
954
+ if (tokens[_i].clazz_l) return tokens[_i].clazz_l;
955
+
956
+ if (tokens[_i].type === TokenType.FullStop) {
957
+ if (l = checkIdent(_i + 1)) {
958
+ tokens[_i].clazz_l = l + 1;
959
+ return l + 1;
960
+ }
961
+ }
962
+
963
+ return fail(tokens[_i]);
964
+ }
965
+
966
+ function getClazz() {
967
+ var startPos = pos;
968
+
969
+ pos++;
970
+
971
+ return needInfo?
972
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.ClazzType, getIdent()] :
973
+ [CSSPNodeType.ClazzType, getIdent()];
974
+ }
975
+
976
+ // node: Combinator
977
+ function checkCombinator(_i) {
978
+ if (tokens[_i].type === TokenType.PlusSign ||
979
+ tokens[_i].type === TokenType.GreaterThanSign ||
980
+ tokens[_i].type === TokenType.Tilde) return 1;
981
+
982
+ return fail(tokens[_i]);
983
+ }
984
+
985
+ function getCombinator() {
986
+ return needInfo?
987
+ [{ ln: tokens[pos].ln }, CSSPNodeType.CombinatorType, tokens[pos++].value] :
988
+ [CSSPNodeType.CombinatorType, tokens[pos++].value];
989
+ }
990
+
991
+ // node: Comment
992
+ function checkComment(_i) {
993
+ if (tokens[_i].type === TokenType.CommentML) return 1;
994
+
995
+ return fail(tokens[_i]);
996
+ }
997
+
998
+ function getComment() {
999
+ var startPos = pos,
1000
+ s = tokens[pos].value.substring(2),
1001
+ l = s.length;
1002
+
1003
+ if (s.charAt(l - 2) === '*' && s.charAt(l - 1) === '/') s = s.substring(0, l - 2);
1004
+
1005
+ pos++;
1006
+
1007
+ return needInfo?
1008
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.CommentType, s] :
1009
+ [CSSPNodeType.CommentType, s];
1010
+ }
1011
+
1012
+ // declaration = property:x ':' value:y -> [#declaration, x, y]
1013
+ function checkDeclaration(_i) {
1014
+ var start = _i,
1015
+ l;
1016
+
1017
+ if (l = checkProperty(_i)) _i += l;
1018
+ else return fail(tokens[_i]);
1019
+
1020
+ if (_i < tokens.length && tokens[_i].type === TokenType.Colon) _i++;
1021
+ else return fail(tokens[_i]);
1022
+
1023
+ if (l = checkValue(_i)) _i += l;
1024
+ else return fail(tokens[_i]);
1025
+
1026
+ return _i - start;
1027
+ }
1028
+
1029
+ function getDeclaration() {
1030
+ var declaration = needInfo?
1031
+ [{ ln: tokens[pos].ln }, CSSPNodeType.DeclarationType, getProperty()] :
1032
+ [CSSPNodeType.DeclarationType, getProperty()];
1033
+
1034
+ pos++;
1035
+
1036
+ declaration.push(getValue());
1037
+
1038
+ return declaration;
1039
+ }
1040
+
1041
+ // node: Decldelim
1042
+ function checkDecldelim(_i) {
1043
+ if (_i < tokens.length && tokens[_i].type === TokenType.Semicolon) return 1;
1044
+
1045
+ return fail(tokens[_i]);
1046
+ }
1047
+
1048
+ function getDecldelim() {
1049
+ var startPos = pos;
1050
+
1051
+ pos++;
1052
+
1053
+ return needInfo?
1054
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.DecldelimType] :
1055
+ [CSSPNodeType.DecldelimType];
1056
+ }
1057
+
1058
+ // node: Delim
1059
+ function checkDelim(_i) {
1060
+ if (_i < tokens.length && tokens[_i].type === TokenType.Comma) return 1;
1061
+
1062
+ if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
1063
+
1064
+ return fail(tokens[_i]);
1065
+ }
1066
+
1067
+ function getDelim() {
1068
+ var startPos = pos;
1069
+
1070
+ pos++;
1071
+
1072
+ return needInfo?
1073
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.DelimType] :
1074
+ [CSSPNodeType.DelimType];
1075
+ }
1076
+
1077
+ // node: Dimension
1078
+ function checkDimension(_i) {
1079
+ var ln = checkNumber(_i),
1080
+ li;
1081
+
1082
+ if (!ln || (ln && _i + ln >= tokens.length)) return fail(tokens[_i]);
1083
+
1084
+ if (li = checkNmName2(_i + ln)) return ln + li;
1085
+
1086
+ return fail(tokens[_i]);
1087
+ }
1088
+
1089
+ function getDimension() {
1090
+ var startPos = pos,
1091
+ n = getNumber(),
1092
+ dimension = needInfo ?
1093
+ [{ ln: tokens[pos].ln }, CSSPNodeType.IdentType, getNmName2()] :
1094
+ [CSSPNodeType.IdentType, getNmName2()];
1095
+
1096
+ return needInfo?
1097
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.DimensionType, n, dimension] :
1098
+ [CSSPNodeType.DimensionType, n, dimension];
1099
+ }
1100
+
1101
+ //filter = filterp:x ':' filterv:y -> [#filter, x, y]
1102
+ function checkFilter(_i) {
1103
+ var start = _i,
1104
+ l;
1105
+
1106
+ if (l = checkFilterp(_i)) _i += l;
1107
+ else return fail(tokens[_i]);
1108
+
1109
+ if (tokens[_i].type === TokenType.Colon) _i++;
1110
+ else return fail(tokens[_i]);
1111
+
1112
+ if (l = checkFilterv(_i)) _i += l;
1113
+ else return fail(tokens[_i]);
1114
+
1115
+ return _i - start;
1116
+ }
1117
+
1118
+ function getFilter() {
1119
+ var filter = needInfo?
1120
+ [{ ln: tokens[pos].ln }, CSSPNodeType.FilterType, getFilterp()] :
1121
+ [CSSPNodeType.FilterType, getFilterp()];
1122
+
1123
+ pos++;
1124
+
1125
+ filter.push(getFilterv());
1126
+
1127
+ return filter;
1128
+ }
1129
+
1130
+ //filterp = (seq('-filter') | seq('_filter') | seq('*filter') | seq('-ms-filter') | seq('filter')):t sc*:s0 -> this.concat([#property, [#ident, t]], s0)
1131
+ function checkFilterp(_i) {
1132
+ var start = _i,
1133
+ l,
1134
+ x;
1135
+
1136
+ if (_i < tokens.length) {
1137
+ if (tokens[_i].value === 'filter') l = 1;
1138
+ else {
1139
+ x = joinValues2(_i, 2);
1140
+
1141
+ if (x === '-filter' || x === '_filter' || x === '*filter') l = 2;
1142
+ else {
1143
+ x = joinValues2(_i, 4);
1144
+
1145
+ if (x === '-ms-filter') l = 4;
1146
+ else return fail(tokens[_i]);
1147
+ }
1148
+ }
1149
+
1150
+ tokens[start].filterp_l = l;
1151
+
1152
+ _i += l;
1153
+
1154
+ if (checkSC(_i)) _i += l;
1155
+
1156
+ return _i - start;
1157
+ }
1158
+
1159
+ return fail(tokens[_i]);
1160
+ }
1161
+
1162
+ function getFilterp() {
1163
+ var startPos = pos,
1164
+ x = joinValues2(pos, tokens[pos].filterp_l),
1165
+ ident = needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.IdentType, x] : [CSSPNodeType.IdentType, x];
1166
+
1167
+ pos += tokens[pos].filterp_l;
1168
+
1169
+ return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.PropertyType, ident] : [CSSPNodeType.PropertyType, ident])
1170
+ .concat(getSC());
1171
+
1172
+ }
1173
+
1174
+ //filterv = progid+:x -> [#filterv].concat(x)
1175
+ function checkFilterv(_i) {
1176
+ var start = _i,
1177
+ l;
1178
+
1179
+ if (l = checkProgid(_i)) _i += l;
1180
+ else return fail(tokens[_i]);
1181
+
1182
+ while (l = checkProgid(_i)) {
1183
+ _i += l;
1184
+ }
1185
+
1186
+ tokens[start].last_progid = _i;
1187
+
1188
+ if (_i < tokens.length && (l = checkSC(_i))) _i += l;
1189
+
1190
+ if (_i < tokens.length && (l = checkImportant(_i))) _i += l;
1191
+
1192
+ return _i - start;
1193
+ }
1194
+
1195
+ function getFilterv() {
1196
+ var filterv = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.FiltervType] : [CSSPNodeType.FiltervType],
1197
+ last_progid = tokens[pos].last_progid;
1198
+
1199
+ while (pos < last_progid) {
1200
+ filterv.push(getProgid());
1201
+ }
1202
+
1203
+ filterv = filterv.concat(checkSC(pos) ? getSC() : []);
1204
+
1205
+ if (pos < tokens.length && checkImportant(pos)) filterv.push(getImportant());
1206
+
1207
+ return filterv;
1208
+ }
1209
+
1210
+ //functionExpression = ``expression('' functionExpressionBody*:x ')' -> [#functionExpression, x.join('')],
1211
+ function checkFunctionExpression(_i) {
1212
+ var start = _i;
1213
+
1214
+ if (!tokens[_i] || tokens[_i++].value !== 'expression') return fail(tokens[_i - 1]);
1215
+
1216
+ if (!tokens[_i] || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i]);
1217
+
1218
+ return tokens[_i].right - start + 1;
1219
+ }
1220
+
1221
+ function getFunctionExpression() {
1222
+ var startPos = pos;
1223
+
1224
+ pos++;
1225
+
1226
+ var e = joinValues(pos + 1, tokens[pos].right - 1);
1227
+
1228
+ pos = tokens[pos].right + 1;
1229
+
1230
+ return needInfo?
1231
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionExpressionType, e] :
1232
+ [CSSPNodeType.FunctionExpressionType, e];
1233
+ }
1234
+
1235
+ //funktion = ident:x '(' functionBody:y ')' -> [#funktion, x, y]
1236
+ function checkFunktion(_i) {
1237
+ var start = _i,
1238
+ l = checkIdent(_i);
1239
+
1240
+ if (!l) return fail(tokens[_i]);
1241
+
1242
+ _i += l;
1243
+
1244
+ if (_i >= tokens.length || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i - 1]);
1245
+
1246
+ return tokens[_i].right - start + 1;
1247
+ }
1248
+
1249
+ function getFunktion() {
1250
+ var startPos = pos,
1251
+ ident = getIdent();
1252
+
1253
+ pos++;
1254
+
1255
+ var body = ident[needInfo? 2 : 1] !== 'not'?
1256
+ getFunctionBody() :
1257
+ getNotFunctionBody(); // ok, here we have CSS3 initial draft: http://dev.w3.org/csswg/selectors3/#negation
1258
+
1259
+ return needInfo?
1260
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.FunktionType, ident, body] :
1261
+ [CSSPNodeType.FunktionType, ident, body];
1262
+ }
1263
+
1264
+ function getFunctionBody() {
1265
+ var startPos = pos,
1266
+ body = [],
1267
+ x;
1268
+
1269
+ while (tokens[pos].type !== TokenType.RightParenthesis) {
1270
+ if (checkTset(pos)) {
1271
+ x = getTset();
1272
+ if ((needInfo && typeof x[1] === 'string') || typeof x[0] === 'string') body.push(x);
1273
+ else body = body.concat(x);
1274
+ } else if (checkClazz(pos)) {
1275
+ body.push(getClazz());
1276
+ } else {
1277
+ throwError();
1278
+ }
1279
+ }
1280
+
1281
+ pos++;
1282
+
1283
+ return (needInfo?
1284
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionBodyType] :
1285
+ [CSSPNodeType.FunctionBodyType]
1286
+ ).concat(body);
1287
+ }
1288
+
1289
+ function getNotFunctionBody() {
1290
+ var startPos = pos,
1291
+ body = [],
1292
+ x;
1293
+
1294
+ while (tokens[pos].type !== TokenType.RightParenthesis) {
1295
+ if (checkSimpleselector(pos)) {
1296
+ body.push(getSimpleSelector());
1297
+ } else {
1298
+ throwError();
1299
+ }
1300
+ }
1301
+
1302
+ pos++;
1303
+
1304
+ return (needInfo?
1305
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionBodyType] :
1306
+ [CSSPNodeType.FunctionBodyType]
1307
+ ).concat(body);
1308
+ }
1309
+
1310
+ // node: Ident
1311
+ function checkIdent(_i) {
1312
+ var start = _i,
1313
+ wasIdent = false;
1314
+
1315
+ // start char / word
1316
+ if (_i < tokens.length &&
1317
+ (tokens[_i].type === TokenType.HyphenMinus ||
1318
+ tokens[_i].type === TokenType.LowLine ||
1319
+ tokens[_i].type === TokenType.Identifier ||
1320
+ tokens[_i].type === TokenType.DollarSign ||
1321
+ tokens[_i].type === TokenType.Asterisk)) _i++;
1322
+ else return fail(tokens[_i]);
1323
+
1324
+ wasIdent = tokens[_i - 1].type === TokenType.Identifier;
1325
+
1326
+ for (; _i < tokens.length; _i++) {
1327
+ if (tokens[_i].type !== TokenType.HyphenMinus &&
1328
+ tokens[_i].type !== TokenType.LowLine) {
1329
+ if (tokens[_i].type !== TokenType.Identifier &&
1330
+ (tokens[_i].type !== TokenType.DecimalNumber || !wasIdent)
1331
+ ) break;
1332
+ else wasIdent = true;
1333
+ }
1334
+ }
1335
+
1336
+ if (!wasIdent && tokens[start].type !== TokenType.Asterisk) return fail(tokens[_i]);
1337
+
1338
+ tokens[start].ident_last = _i - 1;
1339
+
1340
+ return _i - start;
1341
+ }
1342
+
1343
+ function getIdent() {
1344
+ var startPos = pos,
1345
+ s = joinValues(pos, tokens[pos].ident_last);
1346
+
1347
+ pos = tokens[pos].ident_last + 1;
1348
+
1349
+ return needInfo?
1350
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.IdentType, s] :
1351
+ [CSSPNodeType.IdentType, s];
1352
+ }
1353
+
1354
+ //important = '!' sc*:s0 seq('important') -> [#important].concat(s0)
1355
+ function checkImportant(_i) {
1356
+ var start = _i,
1357
+ l;
1358
+
1359
+ if (tokens[_i++].type !== TokenType.ExclamationMark) return fail(tokens[_i - 1]);
1360
+
1361
+ if (l = checkSC(_i)) _i += l;
1362
+
1363
+ if (tokens[_i].value !== 'important') return fail(tokens[_i]);
1364
+
1365
+ return _i - start + 1;
1366
+ }
1367
+
1368
+ function getImportant() {
1369
+ var startPos = pos;
1370
+
1371
+ pos++;
1372
+
1373
+ var sc = getSC();
1374
+
1375
+ pos++;
1376
+
1377
+ return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.ImportantType] : [CSSPNodeType.ImportantType]).concat(sc);
1378
+ }
1379
+
1380
+ // node: Namespace
1381
+ function checkNamespace(_i) {
1382
+ if (tokens[_i].type === TokenType.VerticalLine) return 1;
1383
+
1384
+ return fail(tokens[_i]);
1385
+ }
1386
+
1387
+ function getNamespace() {
1388
+ var startPos = pos;
1389
+
1390
+ pos++;
1391
+
1392
+ return needInfo?
1393
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.NamespaceType] :
1394
+ [CSSPNodeType.NamespaceType];
1395
+ }
1396
+
1397
+ //nth = (digit | 'n')+:x -> [#nth, x.join('')]
1398
+ // | (seq('even') | seq('odd')):x -> [#nth, x]
1399
+ function checkNth(_i) {
1400
+ return checkNth1(_i) || checkNth2(_i);
1401
+ }
1402
+
1403
+ function checkNth1(_i) {
1404
+ var start = _i;
1405
+
1406
+ for (; _i < tokens.length; _i++) {
1407
+ if (tokens[_i].type !== TokenType.DecimalNumber && tokens[_i].value !== 'n') break;
1408
+ }
1409
+
1410
+ if (_i !== start) {
1411
+ tokens[start].nth_last = _i - 1;
1412
+ return _i - start;
1413
+ }
1414
+
1415
+ return fail(tokens[_i]);
1416
+ }
1417
+
1418
+ function getNth() {
1419
+ var startPos = pos;
1420
+
1421
+ if (tokens[pos].nth_last) {
1422
+ var n = needInfo?
1423
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.NthType, joinValues(pos, tokens[pos].nth_last)] :
1424
+ [CSSPNodeType.NthType, joinValues(pos, tokens[pos].nth_last)];
1425
+
1426
+ pos = tokens[pos].nth_last + 1;
1427
+
1428
+ return n;
1429
+ }
1430
+
1431
+ return needInfo?
1432
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.NthType, tokens[pos++].value] :
1433
+ [CSSPNodeType.NthType, tokens[pos++].value];
1434
+ }
1435
+
1436
+ function checkNth2(_i) {
1437
+ if (tokens[_i].value === 'even' || tokens[_i].value === 'odd') return 1;
1438
+
1439
+ return fail(tokens[_i]);
1440
+ }
1441
+
1442
+ //nthf = ':' seq('nth-'):x (seq('child') | seq('last-child') | seq('of-type') | seq('last-of-type')):y -> (x + y)
1443
+ function checkNthf(_i) {
1444
+ var start = _i,
1445
+ l = 0;
1446
+
1447
+ if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]); l++;
1448
+
1449
+ if (tokens[_i++].value !== 'nth' || tokens[_i++].value !== '-') return fail(tokens[_i - 1]); l += 2;
1450
+
1451
+ if ('child' === tokens[_i].value) {
1452
+ l += 1;
1453
+ } else if ('last-child' === tokens[_i].value +
1454
+ tokens[_i + 1].value +
1455
+ tokens[_i + 2].value) {
1456
+ l += 3;
1457
+ } else if ('of-type' === tokens[_i].value +
1458
+ tokens[_i + 1].value +
1459
+ tokens[_i + 2].value) {
1460
+ l += 3;
1461
+ } else if ('last-of-type' === tokens[_i].value +
1462
+ tokens[_i + 1].value +
1463
+ tokens[_i + 2].value +
1464
+ tokens[_i + 3].value +
1465
+ tokens[_i + 4].value) {
1466
+ l += 5;
1467
+ } else return fail(tokens[_i]);
1468
+
1469
+ tokens[start + 1].nthf_last = start + l - 1;
1470
+
1471
+ return l;
1472
+ }
1473
+
1474
+ function getNthf() {
1475
+ pos++;
1476
+
1477
+ var s = joinValues(pos, tokens[pos].nthf_last);
1478
+
1479
+ pos = tokens[pos].nthf_last + 1;
1480
+
1481
+ return s;
1482
+ }
1483
+
1484
+ //nthselector = nthf:x '(' (sc | unary | nth)*:y ')' -> [#nthselector, [#ident, x]].concat(y)
1485
+ function checkNthselector(_i) {
1486
+ var start = _i,
1487
+ l;
1488
+
1489
+ if (l = checkNthf(_i)) _i += l;
1490
+ else return fail(tokens[_i]);
1491
+
1492
+ if (tokens[_i].type !== TokenType.LeftParenthesis || !tokens[_i].right) return fail(tokens[_i]);
1493
+
1494
+ l++;
1495
+
1496
+ var rp = tokens[_i++].right;
1497
+
1498
+ while (_i < rp) {
1499
+ if (l = checkSC(_i)) _i += l;
1500
+ else if (l = checkUnary(_i)) _i += l;
1501
+ else if (l = checkNth(_i)) _i += l;
1502
+ else return fail(tokens[_i]);
1503
+ }
1504
+
1505
+ return rp - start + 1;
1506
+ }
1507
+
1508
+ function getNthselector() {
1509
+ var startPos = pos,
1510
+ nthf = needInfo?
1511
+ [{ ln: tokens[pos].ln }, CSSPNodeType.IdentType, getNthf()] :
1512
+ [CSSPNodeType.IdentType, getNthf()],
1513
+ ns = needInfo?
1514
+ [{ ln: tokens[pos].ln }, CSSPNodeType.NthselectorType, nthf] :
1515
+ [CSSPNodeType.NthselectorType, nthf];
1516
+
1517
+ pos++;
1518
+
1519
+ while (tokens[pos].type !== TokenType.RightParenthesis) {
1520
+ if (checkSC(pos)) ns = ns.concat(getSC());
1521
+ else if (checkUnary(pos)) ns.push(getUnary());
1522
+ else if (checkNth(pos)) ns.push(getNth());
1523
+ }
1524
+
1525
+ pos++;
1526
+
1527
+ return ns;
1528
+ }
1529
+
1530
+ // node: Number
1531
+ function checkNumber(_i) {
1532
+ if (_i < tokens.length && tokens[_i].number_l) return tokens[_i].number_l;
1533
+
1534
+ if (_i < tokens.length && tokens[_i].type === TokenType.DecimalNumber &&
1535
+ (!tokens[_i + 1] ||
1536
+ (tokens[_i + 1] && tokens[_i + 1].type !== TokenType.FullStop))
1537
+ ) return (tokens[_i].number_l = 1, tokens[_i].number_l); // 10
1538
+
1539
+ if (_i < tokens.length &&
1540
+ tokens[_i].type === TokenType.DecimalNumber &&
1541
+ tokens[_i + 1] && tokens[_i + 1].type === TokenType.FullStop &&
1542
+ (!tokens[_i + 2] || (tokens[_i + 2].type !== TokenType.DecimalNumber))
1543
+ ) return (tokens[_i].number_l = 2, tokens[_i].number_l); // 10.
1544
+
1545
+ if (_i < tokens.length &&
1546
+ tokens[_i].type === TokenType.FullStop &&
1547
+ tokens[_i + 1].type === TokenType.DecimalNumber
1548
+ ) return (tokens[_i].number_l = 2, tokens[_i].number_l); // .10
1549
+
1550
+ if (_i < tokens.length &&
1551
+ tokens[_i].type === TokenType.DecimalNumber &&
1552
+ tokens[_i + 1] && tokens[_i + 1].type === TokenType.FullStop &&
1553
+ tokens[_i + 2] && tokens[_i + 2].type === TokenType.DecimalNumber
1554
+ ) return (tokens[_i].number_l = 3, tokens[_i].number_l); // 10.10
1555
+
1556
+ return fail(tokens[_i]);
1557
+ }
1558
+
1559
+ function getNumber() {
1560
+ var s = '',
1561
+ startPos = pos,
1562
+ l = tokens[pos].number_l;
1563
+
1564
+ for (var i = 0; i < l; i++) {
1565
+ s += tokens[pos + i].value;
1566
+ }
1567
+
1568
+ pos += l;
1569
+
1570
+ return needInfo?
1571
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.NumberType, s] :
1572
+ [CSSPNodeType.NumberType, s];
1573
+ }
1574
+
1575
+ // node: Operator
1576
+ function checkOperator(_i) {
1577
+ if (_i < tokens.length &&
1578
+ (tokens[_i].type === TokenType.Solidus ||
1579
+ tokens[_i].type === TokenType.Comma ||
1580
+ tokens[_i].type === TokenType.Colon ||
1581
+ tokens[_i].type === TokenType.EqualsSign)) return 1;
1582
+
1583
+ return fail(tokens[_i]);
1584
+ }
1585
+
1586
+ function getOperator() {
1587
+ return needInfo?
1588
+ [{ ln: tokens[pos].ln }, CSSPNodeType.OperatorType, tokens[pos++].value] :
1589
+ [CSSPNodeType.OperatorType, tokens[pos++].value];
1590
+ }
1591
+
1592
+ // node: Percentage
1593
+ function checkPercentage(_i) {
1594
+ var x = checkNumber(_i);
1595
+
1596
+ if (!x || (x && _i + x >= tokens.length)) return fail(tokens[_i]);
1597
+
1598
+ if (tokens[_i + x].type === TokenType.PercentSign) return x + 1;
1599
+
1600
+ return fail(tokens[_i]);
1601
+ }
1602
+
1603
+ function getPercentage() {
1604
+ var startPos = pos,
1605
+ n = getNumber();
1606
+
1607
+ pos++;
1608
+
1609
+ return needInfo?
1610
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.PercentageType, n] :
1611
+ [CSSPNodeType.PercentageType, n];
1612
+ }
1613
+
1614
+ //progid = sc*:s0 seq('progid:DXImageTransform.Microsoft.'):x letter+:y '(' (m_string | m_comment | ~')' char)+:z ')' sc*:s1
1615
+ // -> this.concat([#progid], s0, [[#raw, x + y.join('') + '(' + z.join('') + ')']], s1),
1616
+ function checkProgid(_i) {
1617
+ var start = _i,
1618
+ l,
1619
+ x;
1620
+
1621
+ if (l = checkSC(_i)) _i += l;
1622
+
1623
+ if ((x = joinValues2(_i, 6)) === 'progid:DXImageTransform.Microsoft.') {
1624
+ _start = _i;
1625
+ _i += 6;
1626
+ } else return fail(tokens[_i - 1]);
1627
+
1628
+ if (l = checkIdent(_i)) _i += l;
1629
+ else return fail(tokens[_i]);
1630
+
1631
+ if (l = checkSC(_i)) _i += l;
1632
+
1633
+ if (tokens[_i].type === TokenType.LeftParenthesis) {
1634
+ tokens[start].progid_end = tokens[_i].right;
1635
+ _i = tokens[_i].right + 1;
1636
+ } else return fail(tokens[_i]);
1637
+
1638
+ if (l = checkSC(_i)) _i += l;
1639
+
1640
+ return _i - start;
1641
+ }
1642
+
1643
+ function getProgid() {
1644
+ var startPos = pos,
1645
+ progid_end = tokens[pos].progid_end;
1646
+
1647
+ return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.ProgidType] : [CSSPNodeType.ProgidType])
1648
+ .concat(getSC())
1649
+ .concat([_getProgid(progid_end)])
1650
+ .concat(getSC());
1651
+ }
1652
+
1653
+ function _getProgid(progid_end) {
1654
+ var startPos = pos,
1655
+ x = joinValues(pos, progid_end);
1656
+
1657
+ pos = progid_end + 1;
1658
+
1659
+ return needInfo?
1660
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.RawType, x] :
1661
+ [CSSPNodeType.RawType, x];
1662
+ }
1663
+
1664
+ //property = ident:x sc*:s0 -> this.concat([#property, x], s0)
1665
+ function checkProperty(_i) {
1666
+ var start = _i,
1667
+ l;
1668
+
1669
+ if (l = checkIdent(_i)) _i += l;
1670
+ else return fail(tokens[_i]);
1671
+
1672
+ if (l = checkSC(_i)) _i += l;
1673
+ return _i - start;
1674
+ }
1675
+
1676
+ function getProperty() {
1677
+ var startPos = pos;
1678
+
1679
+ return (needInfo?
1680
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.PropertyType, getIdent()] :
1681
+ [CSSPNodeType.PropertyType, getIdent()])
1682
+ .concat(getSC());
1683
+ }
1684
+
1685
+ function checkPseudo(_i) {
1686
+ return checkPseudoe(_i) ||
1687
+ checkPseudoc(_i);
1688
+ }
1689
+
1690
+ function getPseudo() {
1691
+ if (checkPseudoe(pos)) return getPseudoe();
1692
+ if (checkPseudoc(pos)) return getPseudoc();
1693
+ }
1694
+
1695
+ function checkPseudoe(_i) {
1696
+ var l;
1697
+
1698
+ if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
1699
+
1700
+ if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
1701
+
1702
+ if (l = checkIdent(_i)) return l + 2;
1703
+
1704
+ return fail(tokens[_i]);
1705
+ }
1706
+
1707
+ function getPseudoe() {
1708
+ var startPos = pos;
1709
+
1710
+ pos += 2;
1711
+
1712
+ return needInfo?
1713
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.PseudoeType, getIdent()] :
1714
+ [CSSPNodeType.PseudoeType, getIdent()];
1715
+ }
1716
+
1717
+ //pseudoc = ':' (funktion | ident):x -> [#pseudoc, x]
1718
+ function checkPseudoc(_i) {
1719
+ var l;
1720
+
1721
+ if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
1722
+
1723
+ if ((l = checkFunktion(_i)) || (l = checkIdent(_i))) return l + 1;
1724
+
1725
+ return fail(tokens[_i]);
1726
+ }
1727
+
1728
+ function getPseudoc() {
1729
+ var startPos = pos;
1730
+
1731
+ pos++;
1732
+
1733
+ return needInfo?
1734
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.PseudocType, checkFunktion(pos)? getFunktion() : getIdent()] :
1735
+ [CSSPNodeType.PseudocType, checkFunktion(pos)? getFunktion() : getIdent()];
1736
+ }
1737
+
1738
+ //ruleset = selector*:x block:y -> this.concat([#ruleset], x, [y])
1739
+ function checkRuleset(_i) {
1740
+ var start = _i,
1741
+ l;
1742
+
1743
+ if (tokens[start].ruleset_l !== undefined) return tokens[start].ruleset_l;
1744
+
1745
+ while (l = checkSelector(_i)) {
1746
+ _i += l;
1747
+ }
1748
+
1749
+ if (l = checkBlock(_i)) _i += l;
1750
+ else return fail(tokens[_i]);
1751
+
1752
+ tokens[start].ruleset_l = _i - start;
1753
+
1754
+ return _i - start;
1755
+ }
1756
+
1757
+ function getRuleset() {
1758
+ var ruleset = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.RulesetType] : [CSSPNodeType.RulesetType];
1759
+
1760
+ while (!checkBlock(pos)) {
1761
+ ruleset.push(getSelector());
1762
+ }
1763
+
1764
+ ruleset.push(getBlock());
1765
+
1766
+ return ruleset;
1767
+ }
1768
+
1769
+ // node: S
1770
+ function checkS(_i) {
1771
+ if (tokens[_i].ws) return tokens[_i].ws_last - _i + 1;
1772
+
1773
+ return fail(tokens[_i]);
1774
+ }
1775
+
1776
+ function getS() {
1777
+ var startPos = pos,
1778
+ s = joinValues(pos, tokens[pos].ws_last);
1779
+
1780
+ pos = tokens[pos].ws_last + 1;
1781
+
1782
+ return needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.SType, s] : [CSSPNodeType.SType, s];
1783
+ }
1784
+
1785
+ function checkSC(_i) {
1786
+ var l,
1787
+ lsc = 0;
1788
+
1789
+ while (_i < tokens.length) {
1790
+ if (!(l = checkS(_i)) && !(l = checkComment(_i))) break;
1791
+ _i += l;
1792
+ lsc += l;
1793
+ }
1794
+
1795
+ if (lsc) return lsc;
1796
+
1797
+ if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
1798
+
1799
+ return fail(tokens[_i]);
1800
+ }
1801
+
1802
+ function getSC() {
1803
+ var sc = [];
1804
+
1805
+ while (pos < tokens.length) {
1806
+ if (checkS(pos)) sc.push(getS());
1807
+ else if (checkComment(pos)) sc.push(getComment());
1808
+ else break;
1809
+ }
1810
+
1811
+ return sc;
1812
+ }
1813
+
1814
+ //selector = (simpleselector | delim)+:x -> this.concat([#selector], x)
1815
+ function checkSelector(_i) {
1816
+ var start = _i,
1817
+ l;
1818
+
1819
+ if (_i < tokens.length) {
1820
+ while (l = checkSimpleselector(_i) || checkDelim(_i)) {
1821
+ _i += l;
1822
+ }
1823
+
1824
+ tokens[start].selector_end = _i - 1;
1825
+
1826
+ return _i - start;
1827
+ }
1828
+ }
1829
+
1830
+ function getSelector() {
1831
+ var selector = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.SelectorType] : [CSSPNodeType.SelectorType],
1832
+ selector_end = tokens[pos].selector_end;
1833
+
1834
+ while (pos <= selector_end) {
1835
+ selector.push(checkDelim(pos) ? getDelim() : getSimpleSelector());
1836
+ }
1837
+
1838
+ return selector;
1839
+ }
1840
+
1841
+ // node: Shash
1842
+ function checkShash(_i) {
1843
+ if (tokens[_i].type !== TokenType.NumberSign) return fail(tokens[_i]);
1844
+
1845
+ var l = checkNmName(_i + 1);
1846
+
1847
+ if (l) return l + 1;
1848
+
1849
+ return fail(tokens[_i]);
1850
+ }
1851
+
1852
+ function getShash() {
1853
+ var startPos = pos;
1854
+
1855
+ pos++;
1856
+
1857
+ return needInfo?
1858
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.ShashType, getNmName()] :
1859
+ [CSSPNodeType.ShashType, getNmName()];
1860
+ }
1861
+
1862
+ //simpleselector = (nthselector | combinator | attrib | pseudo | clazz | shash | any | sc | namespace)+:x -> this.concatContent([#simpleselector], [x])
1863
+ function checkSimpleselector(_i) {
1864
+ var start = _i,
1865
+ l;
1866
+
1867
+ while (_i < tokens.length) {
1868
+ if (l = _checkSimpleSelector(_i)) _i += l;
1869
+ else break;
1870
+ }
1871
+
1872
+ if (_i - start) return _i - start;
1873
+
1874
+ if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
1875
+
1876
+ return fail(tokens[_i]);
1877
+ }
1878
+
1879
+ function _checkSimpleSelector(_i) {
1880
+ return checkNthselector(_i) ||
1881
+ checkCombinator(_i) ||
1882
+ checkAttrib(_i) ||
1883
+ checkPseudo(_i) ||
1884
+ checkClazz(_i) ||
1885
+ checkShash(_i) ||
1886
+ checkAny(_i) ||
1887
+ checkSC(_i) ||
1888
+ checkNamespace(_i);
1889
+ }
1890
+
1891
+ function getSimpleSelector() {
1892
+ var ss = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.SimpleselectorType] : [CSSPNodeType.SimpleselectorType],
1893
+ t;
1894
+
1895
+ while (pos < tokens.length && _checkSimpleSelector(pos)) {
1896
+ t = _getSimpleSelector();
1897
+
1898
+ if ((needInfo && typeof t[1] === 'string') || typeof t[0] === 'string') ss.push(t);
1899
+ else ss = ss.concat(t);
1900
+ }
1901
+
1902
+ return ss;
1903
+ }
1904
+
1905
+ function _getSimpleSelector() {
1906
+ if (checkNthselector(pos)) return getNthselector();
1907
+ else if (checkCombinator(pos)) return getCombinator();
1908
+ else if (checkAttrib(pos)) return getAttrib();
1909
+ else if (checkPseudo(pos)) return getPseudo();
1910
+ else if (checkClazz(pos)) return getClazz();
1911
+ else if (checkShash(pos)) return getShash();
1912
+ else if (checkAny(pos)) return getAny();
1913
+ else if (checkSC(pos)) return getSC();
1914
+ else if (checkNamespace(pos)) return getNamespace();
1915
+ }
1916
+
1917
+ // node: String
1918
+ function checkString(_i) {
1919
+ if (_i < tokens.length &&
1920
+ (tokens[_i].type === TokenType.StringSQ || tokens[_i].type === TokenType.StringDQ)
1921
+ ) return 1;
1922
+
1923
+ return fail(tokens[_i]);
1924
+ }
1925
+
1926
+ function getString() {
1927
+ var startPos = pos;
1928
+
1929
+ return needInfo?
1930
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.StringType, tokens[pos++].value] :
1931
+ [CSSPNodeType.StringType, tokens[pos++].value];
1932
+ }
1933
+
1934
+ //stylesheet = (cdo | cdc | sc | statement)*:x -> this.concat([#stylesheet], x)
1935
+ function checkStylesheet(_i) {
1936
+ var start = _i,
1937
+ l;
1938
+
1939
+ while (_i < tokens.length) {
1940
+ if (l = checkSC(_i)) _i += l;
1941
+ else {
1942
+ currentBlockLN = tokens[_i].ln;
1943
+ if (l = checkAtrule(_i)) _i += l;
1944
+ else if (l = checkRuleset(_i)) _i += l;
1945
+ else if (l = checkUnknown(_i)) _i += l;
1946
+ else throwError();
1947
+ }
1948
+ }
1949
+
1950
+ return _i - start;
1951
+ }
1952
+
1953
+ function getStylesheet(_i) {
1954
+ var t,
1955
+ stylesheet = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.StylesheetType] : [CSSPNodeType.StylesheetType];
1956
+
1957
+ while (pos < tokens.length) {
1958
+ if (checkSC(pos)) stylesheet = stylesheet.concat(getSC());
1959
+ else {
1960
+ currentBlockLN = tokens[pos].ln;
1961
+ if (checkRuleset(pos)) stylesheet.push(getRuleset());
1962
+ else if (checkAtrule(pos)) stylesheet.push(getAtrule());
1963
+ else if (checkUnknown(pos)) stylesheet.push(getUnknown());
1964
+ else throwError();
1965
+ }
1966
+ }
1967
+
1968
+ return stylesheet;
1969
+ }
1970
+
1971
+ //tset = vhash | any | sc | operator
1972
+ function checkTset(_i) {
1973
+ return checkVhash(_i) ||
1974
+ checkAny(_i) ||
1975
+ checkSC(_i) ||
1976
+ checkOperator(_i);
1977
+ }
1978
+
1979
+ function getTset() {
1980
+ if (checkVhash(pos)) return getVhash();
1981
+ else if (checkAny(pos)) return getAny();
1982
+ else if (checkSC(pos)) return getSC();
1983
+ else if (checkOperator(pos)) return getOperator();
1984
+ }
1985
+
1986
+ function checkTsets(_i) {
1987
+ var start = _i,
1988
+ l;
1989
+
1990
+ while (l = checkTset(_i)) {
1991
+ _i += l;
1992
+ }
1993
+
1994
+ return _i - start;
1995
+ }
1996
+
1997
+ function getTsets() {
1998
+ var tsets = [],
1999
+ x;
2000
+
2001
+ while (x = getTset()) {
2002
+ if ((needInfo && typeof x[1] === 'string') || typeof x[0] === 'string') tsets.push(x);
2003
+ else tsets = tsets.concat(x);
2004
+ }
2005
+
2006
+ return tsets;
2007
+ }
2008
+
2009
+ // node: Unary
2010
+ function checkUnary(_i) {
2011
+ if (_i < tokens.length &&
2012
+ (tokens[_i].type === TokenType.HyphenMinus ||
2013
+ tokens[_i].type === TokenType.PlusSign)
2014
+ ) return 1;
2015
+
2016
+ return fail(tokens[_i]);
2017
+ }
2018
+
2019
+ function getUnary() {
2020
+ var startPos = pos;
2021
+
2022
+ return needInfo?
2023
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.UnaryType, tokens[pos++].value] :
2024
+ [CSSPNodeType.UnaryType, tokens[pos++].value];
2025
+ }
2026
+
2027
+ // node: Unknown
2028
+ function checkUnknown(_i) {
2029
+ if (_i < tokens.length && tokens[_i].type === TokenType.CommentSL) return 1;
2030
+
2031
+ return fail(tokens[_i]);
2032
+ }
2033
+
2034
+ function getUnknown() {
2035
+ var startPos = pos;
2036
+
2037
+ return needInfo?
2038
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.UnknownType, tokens[pos++].value] :
2039
+ [CSSPNodeType.UnknownType, tokens[pos++].value];
2040
+ }
2041
+
2042
+ // uri = seq('url(') sc*:s0 string:x sc*:s1 ')' -> this.concat([#uri], s0, [x], s1)
2043
+ // | seq('url(') sc*:s0 (~')' ~m_w char)*:x sc*:s1 ')' -> this.concat([#uri], s0, [[#raw, x.join('')]], s1),
2044
+ function checkUri(_i) {
2045
+ var start = _i,
2046
+ l;
2047
+
2048
+ if (_i < tokens.length && tokens[_i++].value !== 'url') return fail(tokens[_i - 1]);
2049
+
2050
+ if (!tokens[_i] || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i]);
2051
+
2052
+ return tokens[_i].right - start + 1;
2053
+ }
2054
+
2055
+ function getUri() {
2056
+ var startPos = pos,
2057
+ uriExcluding = {};
2058
+
2059
+ pos += 2;
2060
+
2061
+ uriExcluding[TokenType.Space] = 1;
2062
+ uriExcluding[TokenType.Tab] = 1;
2063
+ uriExcluding[TokenType.Newline] = 1;
2064
+ uriExcluding[TokenType.LeftParenthesis] = 1;
2065
+ uriExcluding[TokenType.RightParenthesis] = 1;
2066
+
2067
+ if (checkUri1(pos)) {
2068
+ var uri = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.UriType] : [CSSPNodeType.UriType])
2069
+ .concat(getSC())
2070
+ .concat([getString()])
2071
+ .concat(getSC());
2072
+
2073
+ pos++;
2074
+
2075
+ return uri;
2076
+ } else {
2077
+ var uri = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.UriType] : [CSSPNodeType.UriType])
2078
+ .concat(getSC()),
2079
+ l = checkExcluding(uriExcluding, pos),
2080
+ raw = needInfo?
2081
+ [{ ln: tokens[pos].ln }, CSSPNodeType.RawType, joinValues(pos, pos + l)] :
2082
+ [CSSPNodeType.RawType, joinValues(pos, pos + l)];
2083
+
2084
+ uri.push(raw);
2085
+
2086
+ pos += l + 1;
2087
+
2088
+ uri = uri.concat(getSC());
2089
+
2090
+ pos++;
2091
+
2092
+ return uri;
2093
+ }
2094
+ }
2095
+
2096
+ function checkUri1(_i) {
2097
+ var start = _i,
2098
+ l = checkSC(_i);
2099
+
2100
+ if (l) _i += l;
2101
+
2102
+ if (tokens[_i].type !== TokenType.StringDQ && tokens[_i].type !== TokenType.StringSQ) return fail(tokens[_i]);
2103
+
2104
+ _i++;
2105
+
2106
+ if (l = checkSC(_i)) _i += l;
2107
+
2108
+ return _i - start;
2109
+ }
2110
+
2111
+ // value = (sc | vhash | any | block | atkeyword | operator | important)+:x -> this.concat([#value], x)
2112
+ function checkValue(_i) {
2113
+ var start = _i,
2114
+ l;
2115
+
2116
+ while (_i < tokens.length) {
2117
+ if (l = _checkValue(_i)) _i += l;
2118
+ else break;
2119
+ }
2120
+
2121
+ if (_i - start) return _i - start;
2122
+
2123
+ return fail(tokens[_i]);
2124
+ }
2125
+
2126
+ function _checkValue(_i) {
2127
+ return checkSC(_i) ||
2128
+ checkVhash(_i) ||
2129
+ checkAny(_i) ||
2130
+ checkBlock(_i) ||
2131
+ checkAtkeyword(_i) ||
2132
+ checkOperator(_i) ||
2133
+ checkImportant(_i);
2134
+ }
2135
+
2136
+ function getValue() {
2137
+ var ss = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.ValueType] : [CSSPNodeType.ValueType],
2138
+ t;
2139
+
2140
+ while (pos < tokens.length && _checkValue(pos)) {
2141
+ t = _getValue();
2142
+
2143
+ if ((needInfo && typeof t[1] === 'string') || typeof t[0] === 'string') ss.push(t);
2144
+ else ss = ss.concat(t);
2145
+ }
2146
+
2147
+ return ss;
2148
+ }
2149
+
2150
+ function _getValue() {
2151
+ if (checkSC(pos)) return getSC();
2152
+ else if (checkVhash(pos)) return getVhash();
2153
+ else if (checkAny(pos)) return getAny();
2154
+ else if (checkBlock(pos)) return getBlock();
2155
+ else if (checkAtkeyword(pos)) return getAtkeyword();
2156
+ else if (checkOperator(pos)) return getOperator();
2157
+ else if (checkImportant(pos)) return getImportant();
2158
+ }
2159
+
2160
+ // node: Vhash
2161
+ function checkVhash(_i) {
2162
+ if (_i >= tokens.length || tokens[_i].type !== TokenType.NumberSign) return fail(tokens[_i]);
2163
+
2164
+ var l = checkNmName2(_i + 1);
2165
+
2166
+ if (l) return l + 1;
2167
+
2168
+ return fail(tokens[_i]);
2169
+ }
2170
+
2171
+ function getVhash() {
2172
+ var startPos = pos;
2173
+
2174
+ pos++;
2175
+
2176
+ return needInfo?
2177
+ [{ ln: tokens[startPos].ln }, CSSPNodeType.VhashType, getNmName2()] :
2178
+ [CSSPNodeType.VhashType, getNmName2()];
2179
+ }
2180
+
2181
+ function checkNmName(_i) {
2182
+ var start = _i;
2183
+
2184
+ // start char / word
2185
+ if (tokens[_i].type === TokenType.HyphenMinus ||
2186
+ tokens[_i].type === TokenType.LowLine ||
2187
+ tokens[_i].type === TokenType.Identifier ||
2188
+ tokens[_i].type === TokenType.DecimalNumber) _i++;
2189
+ else return fail(tokens[_i]);
2190
+
2191
+ for (; _i < tokens.length; _i++) {
2192
+ if (tokens[_i].type !== TokenType.HyphenMinus &&
2193
+ tokens[_i].type !== TokenType.LowLine &&
2194
+ tokens[_i].type !== TokenType.Identifier &&
2195
+ tokens[_i].type !== TokenType.DecimalNumber) break;
2196
+ }
2197
+
2198
+ tokens[start].nm_name_last = _i - 1;
2199
+
2200
+ return _i - start;
2201
+ }
2202
+
2203
+ function getNmName() {
2204
+ var s = joinValues(pos, tokens[pos].nm_name_last);
2205
+
2206
+ pos = tokens[pos].nm_name_last + 1;
2207
+
2208
+ return s;
2209
+ }
2210
+
2211
+ function checkNmName2(_i) {
2212
+ var start = _i;
2213
+
2214
+ if (tokens[_i].type === TokenType.Identifier) return 1;
2215
+ else if (tokens[_i].type !== TokenType.DecimalNumber) return fail(tokens[_i]);
2216
+
2217
+ _i++;
2218
+
2219
+ if (!tokens[_i] || tokens[_i].type !== TokenType.Identifier) return 1;
2220
+
2221
+ return 2;
2222
+ }
2223
+
2224
+ function getNmName2() {
2225
+ var s = tokens[pos].value;
2226
+
2227
+ if (tokens[pos++].type === TokenType.DecimalNumber &&
2228
+ pos < tokens.length &&
2229
+ tokens[pos].type === TokenType.Identifier
2230
+ ) s += tokens[pos++].value;
2231
+
2232
+ return s;
2233
+ }
2234
+
2235
+ function checkExcluding(exclude, _i) {
2236
+ var start = _i;
2237
+
2238
+ while(_i < tokens.length) {
2239
+ if (exclude[tokens[_i++].type]) break;
2240
+ }
2241
+
2242
+ return _i - start - 2;
2243
+ }
2244
+
2245
+ function joinValues(start, finish) {
2246
+ var s = '';
2247
+
2248
+ for (var i = start; i < finish + 1; i++) {
2249
+ s += tokens[i].value;
2250
+ }
2251
+
2252
+ return s;
2253
+ }
2254
+
2255
+ function joinValues2(start, num) {
2256
+ if (start + num - 1 >= tokens.length) return;
2257
+
2258
+ var s = '';
2259
+
2260
+ for (var i = 0; i < num; i++) {
2261
+ s += tokens[start + i].value;
2262
+ }
2263
+
2264
+ return s;
2265
+ }
2266
+
2267
+ function markSC() {
2268
+ var ws = -1, // whitespaces
2269
+ sc = -1, // ws and comments
2270
+ t;
2271
+
2272
+ for (var i = 0; i < tokens.length; i++) {
2273
+ t = tokens[i];
2274
+ switch (t.type) {
2275
+ case TokenType.Space:
2276
+ case TokenType.Tab:
2277
+ case TokenType.Newline:
2278
+ t.ws = true;
2279
+ t.sc = true;
2280
+
2281
+ if (ws === -1) ws = i;
2282
+ if (sc === -1) sc = i;
2283
+
2284
+ break;
2285
+ case TokenType.CommentML:
2286
+ if (ws !== -1) {
2287
+ tokens[ws].ws_last = i - 1;
2288
+ ws = -1;
2289
+ }
2290
+
2291
+ t.sc = true;
2292
+
2293
+ break;
2294
+ default:
2295
+ if (ws !== -1) {
2296
+ tokens[ws].ws_last = i - 1;
2297
+ ws = -1;
2298
+ }
2299
+
2300
+ if (sc !== -1) {
2301
+ tokens[sc].sc_last = i - 1;
2302
+ sc = -1;
2303
+ }
2304
+ }
2305
+ }
2306
+
2307
+ if (ws !== -1) tokens[ws].ws_last = i - 1;
2308
+ if (sc !== -1) tokens[sc].sc_last = i - 1;
2309
+ }
2310
+
2311
+ return _getAST(_tokens, rule, _needInfo);
2312
+ }
2313
+
2314
+ return getCSSPAST(getTokens(s), rule, _needInfo);
2315
+ }
2316
+ var translator = new CSSOTranslator(),
2317
+ cleanInfo = $util.cleanInfo;
2318
+ function TRBL(name, imp) {
2319
+ this.name = TRBL.extractMain(name);
2320
+ this.sides = {
2321
+ 'top': null,
2322
+ 'right': null,
2323
+ 'bottom': null,
2324
+ 'left': null
2325
+ };
2326
+ this.imp = imp ? 4 : 0;
2327
+ }
2328
+
2329
+ TRBL.props = {
2330
+ 'margin': 1,
2331
+ 'margin-top': 1,
2332
+ 'margin-right': 1,
2333
+ 'margin-bottom': 1,
2334
+ 'margin-left': 1,
2335
+ 'padding': 1,
2336
+ 'padding-top': 1,
2337
+ 'padding-right': 1,
2338
+ 'padding-bottom': 1,
2339
+ 'padding-left': 1
2340
+ };
2341
+
2342
+ TRBL.extractMain = function(name) {
2343
+ var i = name.indexOf('-');
2344
+ return i === -1 ? name : name.substr(0, i);
2345
+ };
2346
+
2347
+ TRBL.prototype.impSum = function() {
2348
+ var imp = 0, n = 0;
2349
+ for (var k in this.sides) {
2350
+ if (this.sides[k]) {
2351
+ n++;
2352
+ if (this.sides[k].imp) imp++;
2353
+ }
2354
+ }
2355
+ return imp === n ? imp : 0;
2356
+ };
2357
+
2358
+ TRBL.prototype.add = function(name, sValue, tValue, imp) {
2359
+ var s = this.sides,
2360
+ currentSide,
2361
+ i, x, side, a = [], last,
2362
+ imp = imp ? 1 : 0,
2363
+ wasUnary = false;
2364
+ if ((i = name.lastIndexOf('-')) !== -1) {
2365
+ side = name.substr(i + 1);
2366
+ if (side in s) {
2367
+ if (!(currentSide = s[side]) || (imp && !currentSide.imp)) {
2368
+ s[side] = { s: imp ? sValue.substring(0, sValue.length - 10) : sValue, t: [tValue[0]], imp: imp };
2369
+ if (tValue[0][1] === 'unary') s[side].t.push(tValue[1]);
2370
+ }
2371
+ return true;
2372
+ }
2373
+ } else if (name === this.name) {
2374
+ for (i = 0; i < tValue.length; i++) {
2375
+ x = tValue[i];
2376
+ last = a[a.length - 1];
2377
+ switch(x[1]) {
2378
+ case 'unary':
2379
+ a.push({ s: x[2], t: [x], imp: imp });
2380
+ wasUnary = true;
2381
+ break;
2382
+ case 'number':
2383
+ case 'ident':
2384
+ if (wasUnary) {
2385
+ last.t.push(x);
2386
+ last.s += x[2];
2387
+ } else {
2388
+ a.push({ s: x[2], t: [x], imp: imp });
2389
+ }
2390
+ wasUnary = false;
2391
+ break;
2392
+ case 'percentage':
2393
+ if (wasUnary) {
2394
+ last.t.push(x);
2395
+ last.s += x[2][2] + '%';
2396
+ } else {
2397
+ a.push({ s: x[2][2] + '%', t: [x], imp: imp });
2398
+ }
2399
+ wasUnary = false;
2400
+ break;
2401
+ case 'dimension':
2402
+ if (wasUnary) {
2403
+ last.t.push(x);
2404
+ last.s += x[2][2] + x[3][2];
2405
+ } else {
2406
+ a.push({ s: x[2][2] + x[3][2], t: [x], imp: imp });
2407
+ }
2408
+ wasUnary = false;
2409
+ break;
2410
+ case 's':
2411
+ case 'comment':
2412
+ case 'important':
2413
+ break;
2414
+ default:
2415
+ return false;
2416
+ }
2417
+ }
2418
+
2419
+ if (a.length > 4) return false;
2420
+
2421
+ if (!a[1]) a[1] = a[0];
2422
+ if (!a[2]) a[2] = a[0];
2423
+ if (!a[3]) a[3] = a[1];
2424
+
2425
+ if (!s.top) s.top = a[0];
2426
+ if (!s.right) s.right = a[1];
2427
+ if (!s.bottom) s.bottom = a[2];
2428
+ if (!s.left) s.left = a[3];
2429
+
2430
+ return true;
2431
+ }
2432
+ };
2433
+
2434
+ TRBL.prototype.isOkToMinimize = function() {
2435
+ var s = this.sides,
2436
+ imp;
2437
+
2438
+ if (!!(s.top && s.right && s.bottom && s.left)) {
2439
+ imp = s.top.imp + s.right.imp + s.bottom.imp + s.left.imp;
2440
+ return (imp === 0 || imp === 4 || imp === this.imp);
2441
+ }
2442
+ return false;
2443
+ };
2444
+
2445
+ TRBL.prototype.getValue = function() {
2446
+ var s = this.sides,
2447
+ a = [s.top, s.right, s.bottom, s.left],
2448
+ r = [{}, 'value'];
2449
+
2450
+ if (s.left.s === s.right.s) {
2451
+ a.length--;
2452
+ if (s.bottom.s === s.top.s) {
2453
+ a.length--;
2454
+ if (s.right.s === s.top.s) {
2455
+ a.length--;
2456
+ }
2457
+ }
2458
+ }
2459
+
2460
+ for (var i = 0; i < a.length - 1; i++) {
2461
+ r = r.concat(a[i].t);
2462
+ r.push([{ s: ' ' }, 's', ' ']);
2463
+ }
2464
+ r = r.concat(a[i].t);
2465
+
2466
+ if (this.impSum()) r.push([{ s: '!important'}, 'important']);
2467
+
2468
+ return r;
2469
+ };
2470
+
2471
+ TRBL.prototype.getProperty = function() {
2472
+ return [{ s: this.name }, 'property', [{ s: this.name }, 'ident', this.name]];
2473
+ };
2474
+
2475
+ TRBL.prototype.getString = function() {
2476
+ var p = this.getProperty(),
2477
+ v = this.getValue().slice(2),
2478
+ r = p[0].s + ':';
2479
+
2480
+ for (var i = 0; i < v.length; i++) r += v[i][0].s;
2481
+
2482
+ return r;
2483
+ };
2484
+
2485
+ function CSSOCompressor() {}
2486
+
2487
+ CSSOCompressor.prototype.init = function() {
2488
+ this.props = {};
2489
+ this.shorts = {};
2490
+ this.shorts2 = {};
2491
+
2492
+ this.ccrules = {}; // clean comment rules — special case to resolve ambiguity
2493
+ this.crules = {}; // compress rules
2494
+ this.prules = {}; // prepare rules
2495
+ this.frrules = {}; // freeze ruleset rules
2496
+ this.msrules = {}; // mark shorthands rules
2497
+ this.csrules = {}; // clean shorthands rules
2498
+ this.rbrules = {}; // restructure block rules
2499
+ this.rjrules = {}; // rejoin ruleset rules
2500
+ this.rrrules = {}; // restructure ruleset rules
2501
+ this.frules = {}; // finalize rules
2502
+
2503
+ this.initRules(this.crules, this.defCCfg);
2504
+ this.initRules(this.ccrules, this.cleanCfg);
2505
+ this.initRules(this.frrules, this.frCfg);
2506
+ this.initRules(this.prules, this.preCfg);
2507
+ this.initRules(this.msrules, this.msCfg);
2508
+ this.initRules(this.csrules, this.csCfg);
2509
+ this.initRules(this.rbrules, this.defRBCfg);
2510
+ this.initRules(this.rjrules, this.defRJCfg);
2511
+ this.initRules(this.rrrules, this.defRRCfg);
2512
+ this.initRules(this.frules, this.defFCfg);
2513
+
2514
+ this.shortGroupID = 0;
2515
+ this.lastShortGroupID = 0;
2516
+ this.lastShortSelector = 0;
2517
+ };
2518
+
2519
+ CSSOCompressor.prototype.initRules = function(r, cfg) {
2520
+ var o = this.order,
2521
+ p = this.profile,
2522
+ x, i, k,
2523
+ t = [];
2524
+
2525
+ for (i = 0; i < o.length; i++) if (o[i] in cfg) t.push(o[i]);
2526
+
2527
+ if (!t.length) t = o;
2528
+ for (i = 0; i < t.length; i++) {
2529
+ x = p[t[i]];
2530
+ for (k in x) r[k] ? r[k].push(t[i]) : r[k] = [t[i]];
2531
+ }
2532
+ };
2533
+
2534
+ CSSOCompressor.prototype.cleanCfg = {
2535
+ 'cleanComment': 1
2536
+ };
2537
+
2538
+ CSSOCompressor.prototype.defCCfg = {
2539
+ 'cleanCharset': 1,
2540
+ 'cleanImport': 1,
2541
+ 'cleanWhitespace': 1,
2542
+ 'cleanDecldelim': 1,
2543
+ 'compressNumber': 1,
2544
+ 'cleanUnary': 1,
2545
+ 'compressColor': 1,
2546
+ 'compressDimension': 1,
2547
+ 'compressString': 1,
2548
+ 'compressFontWeight': 1,
2549
+ 'compressFont': 1,
2550
+ 'compressBackground': 1,
2551
+ 'cleanEmpty': 1
2552
+ };
2553
+
2554
+ CSSOCompressor.prototype.defRBCfg = {
2555
+ 'restructureBlock': 1
2556
+ };
2557
+
2558
+ CSSOCompressor.prototype.defRJCfg = {
2559
+ 'rejoinRuleset': 1,
2560
+ 'cleanEmpty': 1
2561
+ };
2562
+
2563
+ CSSOCompressor.prototype.defRRCfg = {
2564
+ 'restructureRuleset': 1,
2565
+ 'cleanEmpty': 1
2566
+ };
2567
+
2568
+ CSSOCompressor.prototype.defFCfg = {
2569
+ 'cleanEmpty': 1,
2570
+ 'delimSelectors': 1,
2571
+ 'delimBlocks': 1
2572
+ };
2573
+
2574
+ CSSOCompressor.prototype.preCfg = {
2575
+ 'destroyDelims': 1,
2576
+ 'preTranslate': 1
2577
+ };
2578
+
2579
+ CSSOCompressor.prototype.msCfg = {
2580
+ 'markShorthands': 1
2581
+ };
2582
+
2583
+ CSSOCompressor.prototype.frCfg = {
2584
+ 'freezeRulesets': 1
2585
+ };
2586
+
2587
+ CSSOCompressor.prototype.csCfg = {
2588
+ 'cleanShorthands': 1,
2589
+ 'cleanEmpty': 1
2590
+ };
2591
+
2592
+ CSSOCompressor.prototype.order = [
2593
+ 'cleanCharset',
2594
+ 'cleanImport',
2595
+ 'cleanComment',
2596
+ 'cleanWhitespace',
2597
+ 'compressNumber',
2598
+ 'cleanUnary',
2599
+ 'compressColor',
2600
+ 'compressDimension',
2601
+ 'compressString',
2602
+ 'compressFontWeight',
2603
+ 'compressFont',
2604
+ 'compressBackground',
2605
+ 'freezeRulesets',
2606
+ 'destroyDelims',
2607
+ 'preTranslate',
2608
+ 'markShorthands',
2609
+ 'cleanShorthands',
2610
+ 'restructureBlock',
2611
+ 'rejoinRuleset',
2612
+ 'restructureRuleset',
2613
+ 'cleanEmpty',
2614
+ 'delimSelectors',
2615
+ 'delimBlocks'
2616
+ ];
2617
+
2618
+ CSSOCompressor.prototype.profile = {
2619
+ 'cleanCharset': {
2620
+ 'atrules': 1
2621
+ },
2622
+ 'cleanImport': {
2623
+ 'atrules': 1
2624
+ },
2625
+ 'cleanWhitespace': {
2626
+ 's': 1
2627
+ },
2628
+ 'compressNumber': {
2629
+ 'number': 1
2630
+ },
2631
+ 'cleanUnary': {
2632
+ 'unary': 1
2633
+ },
2634
+ 'compressColor': {
2635
+ 'vhash': 1,
2636
+ 'funktion': 1,
2637
+ 'ident': 1
2638
+ },
2639
+ 'compressDimension': {
2640
+ 'dimension': 1
2641
+ },
2642
+ 'compressString': {
2643
+ 'string': 1
2644
+ },
2645
+ 'compressFontWeight': {
2646
+ 'declaration': 1
2647
+ },
2648
+ 'compressFont': {
2649
+ 'declaration': 1
2650
+ },
2651
+ 'compressBackground': {
2652
+ 'declaration': 1
2653
+ },
2654
+ 'cleanComment': {
2655
+ 'comment': 1
2656
+ },
2657
+ 'cleanDecldelim': {
2658
+ 'block': 1
2659
+ },
2660
+ 'cleanEmpty': {
2661
+ 'ruleset': 1,
2662
+ 'atruleb': 1,
2663
+ 'atruler': 1
2664
+ },
2665
+ 'destroyDelims': {
2666
+ 'decldelim': 1,
2667
+ 'delim': 1
2668
+ },
2669
+ 'preTranslate': {
2670
+ 'declaration': 1,
2671
+ 'property': 1,
2672
+ 'simpleselector': 1,
2673
+ 'filter': 1,
2674
+ 'value': 1,
2675
+ 'number': 1,
2676
+ 'percentage': 1,
2677
+ 'dimension': 1,
2678
+ 'ident': 1
2679
+ },
2680
+ 'restructureBlock': {
2681
+ 'block': 1
2682
+ },
2683
+ 'rejoinRuleset': {
2684
+ 'ruleset': 1
2685
+ },
2686
+ 'restructureRuleset': {
2687
+ 'ruleset': 1
2688
+ },
2689
+ 'delimSelectors': {
2690
+ 'selector': 1
2691
+ },
2692
+ 'delimBlocks': {
2693
+ 'block': 1
2694
+ },
2695
+ 'markShorthands': {
2696
+ 'block': 1
2697
+ },
2698
+ 'cleanShorthands': {
2699
+ 'declaration': 1
2700
+ },
2701
+ 'freezeRulesets': {
2702
+ 'ruleset': 1
2703
+ }
2704
+ };
2705
+
2706
+ CSSOCompressor.prototype.isContainer = function(o) {
2707
+ if (Array.isArray(o)) {
2708
+ for (var i = 0; i < o.length; i++) if (Array.isArray(o[i])) return true;
2709
+ }
2710
+ };
2711
+
2712
+ CSSOCompressor.prototype.process = function(rules, token, container, i, path) {
2713
+ var rule = token[1];
2714
+ if (rule && rules[rule]) {
2715
+ var r = rules[rule],
2716
+ x1 = token, x2,
2717
+ o = this.order, k;
2718
+ for (var k = 0; k < r.length; k++) {
2719
+ x2 = this[r[k]](x1, rule, container, i, path);
2720
+ if (x2 === null) return null;
2721
+ else if (x2 !== undefined) x1 = x2;
2722
+ }
2723
+ }
2724
+ return x1;
2725
+ };
2726
+
2727
+ CSSOCompressor.prototype.compress = function(tree, ro) {
2728
+ tree = tree || ['stylesheet'];
2729
+ this.init();
2730
+ this.info = true;
2731
+
2732
+ var x = (typeof tree[0] !== 'string') ? tree : this.injectInfo([tree])[0],
2733
+ l0, l1 = 100000000000, ls,
2734
+ x0, x1, xs,
2735
+ protectedComment = this.findProtectedComment(tree);
2736
+
2737
+ // compression without restructure
2738
+ x = this.walk(this.ccrules, x, '/0');
2739
+ x = this.walk(this.crules, x, '/0');
2740
+ x = this.walk(this.prules, x, '/0');
2741
+ x = this.walk(this.frrules, x, '/0');
2742
+
2743
+ ls = translator.translate(cleanInfo(x)).length;
2744
+
2745
+ if (!ro) { // restructure ON
2746
+ xs = this.copyArray(x);
2747
+ x = this.walk(this.rjrules, x, '/0');
2748
+ this.disjoin(x);
2749
+ x = this.walk(this.msrules, x, '/0');
2750
+ x = this.walk(this.csrules, x, '/0');
2751
+ x = this.walk(this.rbrules, x, '/0');
2752
+ do {
2753
+ l0 = l1;
2754
+ x0 = this.copyArray(x);
2755
+ x = this.walk(this.rjrules, x, '/0');
2756
+ x = this.walk(this.rrrules, x, '/0');
2757
+ l1 = translator.translate(cleanInfo(x)).length;
2758
+ x1 = this.copyArray(x);
2759
+ } while (l0 > l1);
2760
+ if (ls < l0 && ls < l1) x = xs;
2761
+ else if (l0 < l1) x = x0;
2762
+ }
2763
+
2764
+ x = this.walk(this.frules, x, '/0');
2765
+
2766
+ if (protectedComment) x.splice(2, 0, protectedComment);
2767
+
2768
+ return x;
2769
+ };
2770
+
2771
+ CSSOCompressor.prototype.findProtectedComment = function(tree) {
2772
+ var token;
2773
+ for (var i = 2; i < tree.length; i++) {
2774
+ token = tree[i];
2775
+ if (token[1] === 'comment' && token[2].length > 0 && token[2].charAt(0) === '!') return token;
2776
+ if (token[1] !== 's') return;
2777
+ }
2778
+ };
2779
+
2780
+ CSSOCompressor.prototype.injectInfo = function(token) {
2781
+ var t;
2782
+ for (var i = token.length - 1; i > -1; i--) {
2783
+ t = token[i];
2784
+ if (t && Array.isArray(t)) {
2785
+ if (this.isContainer(t)) t = this.injectInfo(t);
2786
+ t.splice(0, 0, {});
2787
+ }
2788
+ }
2789
+ return token;
2790
+ };
2791
+
2792
+ CSSOCompressor.prototype.disjoin = function(container) {
2793
+ var t, s, r, sr;
2794
+
2795
+ for (var i = container.length - 1; i > -1; i--) {
2796
+ t = container[i];
2797
+ if (t && Array.isArray(t)) {
2798
+ if (t[1] === 'ruleset') {
2799
+ t[0].shortGroupID = this.shortGroupID++;
2800
+ s = t[2];
2801
+ if (s.length > 3) {
2802
+ sr = s.slice(0, 2);
2803
+ for (var k = s.length - 1; k > 1; k--) {
2804
+ r = this.copyArray(t);
2805
+ r[2] = sr.concat([s[k]]);
2806
+ r[2][0].s = s[k][0].s;
2807
+ container.splice(i + 1, 0, r);
2808
+ }
2809
+ container.splice(i, 1);
2810
+ }
2811
+ }
2812
+ }
2813
+ if (this.isContainer(t)) this.disjoin(t);
2814
+ }
2815
+ };
2816
+
2817
+ CSSOCompressor.prototype.walk = function(rules, container, path) {
2818
+ var t, x;
2819
+ for (var i = container.length - 1; i > -1; i--) {
2820
+ t = container[i];
2821
+ if (t && Array.isArray(t)) {
2822
+ t[0].parent = container;
2823
+ if (this.isContainer(t)) t = this.walk(rules, t, path + '/' + i); // go inside
2824
+ if (t === null) container.splice(i, 1);
2825
+ else {
2826
+ if (x = this.process(rules, t, container, i, path)) container[i] = x; // compressed not null
2827
+ else if (x === null) container.splice(i, 1); // null is the mark to delete token
2828
+ }
2829
+ }
2830
+ }
2831
+ return container.length ? container : null;
2832
+ };
2833
+
2834
+ CSSOCompressor.prototype.freezeRulesets = function(token, rule, container, i) {
2835
+ var info = token[0],
2836
+ selector = token[2];
2837
+
2838
+ info.freeze = this.freezeNeeded(selector);
2839
+ info.freezeID = this.selectorSignature(selector);
2840
+ info.pseudoID = this.composePseudoID(selector);
2841
+ this.markSimplePseudo(selector);
2842
+
2843
+ return token;
2844
+ };
2845
+
2846
+ CSSOCompressor.prototype.markSimplePseudo = function(selector) {
2847
+ var ss, sg = {};
2848
+
2849
+ for (var i = 2; i < selector.length; i++) {
2850
+ ss = selector[i];
2851
+ ss[0].pseudo = this.containsPseudo(ss);
2852
+ ss[0].sg = sg;
2853
+ sg[ss[0].s] = 1;
2854
+ }
2855
+ };
2856
+
2857
+ CSSOCompressor.prototype.composePseudoID = function(selector) {
2858
+ var a = [], ss;
2859
+
2860
+ for (var i = 2; i < selector.length; i++) {
2861
+ ss = selector[i];
2862
+ if (this.containsPseudo(ss)) {
2863
+ a.push(ss[0].s);
2864
+ }
2865
+ }
2866
+
2867
+ a.sort();
2868
+
2869
+ return a.join(',');
2870
+ };
2871
+
2872
+ CSSOCompressor.prototype.containsPseudo = function(sselector) {
2873
+ for (var j = 2; j < sselector.length; j++) {
2874
+ switch (sselector[j][1]) {
2875
+ case 'pseudoc':
2876
+ case 'pseudoe':
2877
+ case 'nthselector':
2878
+ if (!(sselector[j][2][2] in this.notFPClasses)) return true;
2879
+ }
2880
+ }
2881
+ };
2882
+
2883
+ CSSOCompressor.prototype.selectorSignature = function(selector) {
2884
+ var a = [];
2885
+
2886
+ for (var i = 2; i < selector.length; i++) {
2887
+ a.push(translator.translate(cleanInfo(selector[i])));
2888
+ }
2889
+
2890
+ a.sort();
2891
+
2892
+ return a.join(',');
2893
+ };
2894
+
2895
+ CSSOCompressor.prototype.pseudoSelectorSignature = function(selector, exclude) {
2896
+ var a = [], b = {}, ss, wasExclude = false;
2897
+ exclude = exclude || {};
2898
+
2899
+ for (var i = 2; i < selector.length; i++) {
2900
+ ss = selector[i];
2901
+ for (var j = 2; j < ss.length; j++) {
2902
+ switch (ss[j][1]) {
2903
+ case 'pseudoc':
2904
+ case 'pseudoe':
2905
+ case 'nthselector':
2906
+ if (!(ss[j][2][2] in exclude)) b[ss[j][2][2]] = 1;
2907
+ else wasExclude = true;
2908
+ break;
2909
+ }
2910
+ }
2911
+ }
2912
+
2913
+ for (var k in b) a.push(k);
2914
+
2915
+ a.sort();
2916
+
2917
+ return a.join(',') + wasExclude;
2918
+ };
2919
+
2920
+ CSSOCompressor.prototype.notFPClasses = {
2921
+ 'link': 1,
2922
+ 'visited': 1,
2923
+ 'hover': 1,
2924
+ 'active': 1,
2925
+ 'first-letter': 1,
2926
+ 'first-line': 1
2927
+ };
2928
+
2929
+ CSSOCompressor.prototype.notFPElements = {
2930
+ 'first-letter': 1,
2931
+ 'first-line': 1
2932
+ };
2933
+
2934
+ CSSOCompressor.prototype.freezeNeeded = function(selector) {
2935
+ var ss;
2936
+ for (var i = 2; i < selector.length; i++) {
2937
+ ss = selector[i];
2938
+ for (var j = 2; j < ss.length; j++) {
2939
+ switch (ss[j][1]) {
2940
+ case 'pseudoc':
2941
+ if (!(ss[j][2][2] in this.notFPClasses)) return true;
2942
+ break;
2943
+ case 'pseudoe':
2944
+ if (!(ss[j][2][2] in this.notFPElements)) return true;
2945
+ break;
2946
+ case 'nthselector':
2947
+ return true;
2948
+ break;
2949
+ }
2950
+ }
2951
+ }
2952
+ return false;
2953
+ };
2954
+
2955
+ CSSOCompressor.prototype.cleanCharset = function(token, rule, container, i) {
2956
+ if (token[2][2][2] === 'charset') {
2957
+ for (i = i - 1; i > 1; i--) {
2958
+ if (container[i][1] !== 's' && container[i][1] !== 'comment') return null;
2959
+ }
2960
+ }
2961
+ };
2962
+
2963
+ CSSOCompressor.prototype.cleanImport = function(token, rule, container, i) {
2964
+ var x;
2965
+ for (i = i - 1; i > 1; i--) {
2966
+ x = container[i][1];
2967
+ if (x !== 's' && x !== 'comment') {
2968
+ if (x === 'atrules') {
2969
+ x = container[i][2][2][2];
2970
+ if (x !== 'import' && x !== 'charset') return null;
2971
+ } else return null;
2972
+ }
2973
+ }
2974
+ };
2975
+
2976
+ CSSOCompressor.prototype.cleanComment = function(token, rule, container, i) {
2977
+ var pr = ((container[1] === 'braces' && i === 4) ||
2978
+ (container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
2979
+ nr = i === container.length - 1 ? null : container[i + 1][1];
2980
+
2981
+ if (nr !== null && pr !== null) {
2982
+ if (this._cleanComment(nr) || this._cleanComment(pr)) return null;
2983
+ } else return null;
2984
+ };
2985
+
2986
+ CSSOCompressor.prototype._cleanComment = function(r) {
2987
+ switch(r) {
2988
+ case 's':
2989
+ case 'operator':
2990
+ case 'attrselector':
2991
+ case 'block':
2992
+ case 'decldelim':
2993
+ case 'ruleset':
2994
+ case 'declaration':
2995
+ case 'atruleb':
2996
+ case 'atrules':
2997
+ case 'atruler':
2998
+ case 'important':
2999
+ case 'nth':
3000
+ case 'combinator':
3001
+ return true;
3002
+ }
3003
+ };
3004
+
3005
+ CSSOCompressor.prototype.nextToken = function(container, type, i, exactly) {
3006
+ var t, r;
3007
+ for (; i < container.length; i++) {
3008
+ t = container[i];
3009
+ if (Array.isArray(t)) {
3010
+ r = t[1];
3011
+ if (r === type) return t;
3012
+ else if (exactly && r !== 's') return;
3013
+ }
3014
+ }
3015
+ };
3016
+
3017
+ CSSOCompressor.prototype.cleanWhitespace = function(token, rule, container, i) {
3018
+ var pr = ((container[1] === 'braces' && i === 4) ||
3019
+ (container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
3020
+ nr = i === container.length - 1 ? null : container[i + 1][1];
3021
+
3022
+ if (nr === 'unknown') token[2] = '\n';
3023
+ else {
3024
+ if (!(container[1] === 'atrulerq' && !pr) && !this.issue16(container, i)) {
3025
+ if (nr !== null && pr !== null) {
3026
+ if (this._cleanWhitespace(nr, false) || this._cleanWhitespace(pr, true)) return null;
3027
+ } else return null;
3028
+ }
3029
+
3030
+ token[2] = ' ';
3031
+ }
3032
+
3033
+ return token;
3034
+ };
3035
+
3036
+ // See https://github.com/afelix/csso/issues/16
3037
+ CSSOCompressor.prototype.issue16 = function(container, i) {
3038
+ return (i !== 2 && i !== container.length - 1 && container[i - 1][1] === 'uri');
3039
+ };
3040
+
3041
+ CSSOCompressor.prototype._cleanWhitespace = function(r, left) {
3042
+ switch(r) {
3043
+ case 's':
3044
+ case 'operator':
3045
+ case 'attrselector':
3046
+ case 'block':
3047
+ case 'decldelim':
3048
+ case 'ruleset':
3049
+ case 'declaration':
3050
+ case 'atruleb':
3051
+ case 'atrules':
3052
+ case 'atruler':
3053
+ case 'important':
3054
+ case 'nth':
3055
+ case 'combinator':
3056
+ return true;
3057
+ }
3058
+ if (left) {
3059
+ switch(r) {
3060
+ case 'funktion':
3061
+ case 'braces':
3062
+ case 'uri':
3063
+ return true;
3064
+ }
3065
+ }
3066
+ };
3067
+
3068
+ CSSOCompressor.prototype.cleanDecldelim = function(token) {
3069
+ for (var i = token.length - 1; i > 1; i--) {
3070
+ if (token[i][1] === 'decldelim' &&
3071
+ token[i + 1][1] !== 'declaration') token.splice(i, 1);
3072
+ }
3073
+ if (token[2][1] === 'decldelim') token.splice(2, 1);
3074
+ return token;
3075
+ };
3076
+
3077
+ CSSOCompressor.prototype.compressNumber = function(token, rule, container, i) {
3078
+ var x = token[2];
3079
+
3080
+ if (/^0*/.test(x)) x = x.replace(/^0+/, '');
3081
+ if (/\.0*$/.test(x)) x = x.replace(/\.0*$/, '');
3082
+ if (/\..*[1-9]+0+$/.test(x)) x = x.replace(/0+$/, '');
3083
+ if (x === '.' || x === '') x = '0';
3084
+
3085
+ token[2] = x;
3086
+ token[0].s = x;
3087
+ return token;
3088
+ };
3089
+
3090
+ CSSOCompressor.prototype.findDeclaration = function(token) {
3091
+ var parent = token;
3092
+ while ((parent = parent[0].parent) && parent[1] !== 'declaration');
3093
+ return parent;
3094
+ };
3095
+
3096
+ CSSOCompressor.prototype.cleanUnary = function(token, rule, container, i) {
3097
+ var next = container[i + 1];
3098
+ if (next && next[1] === 'number' && next[2] === '0') return null;
3099
+ return token;
3100
+ };
3101
+
3102
+ CSSOCompressor.prototype.compressColor = function(token, rule, container, i) {
3103
+ switch(rule) {
3104
+ case 'vhash':
3105
+ return this.compressHashColor(token);
3106
+ case 'funktion':
3107
+ return this.compressFunctionColor(token);
3108
+ case 'ident':
3109
+ return this.compressIdentColor(token, rule, container, i);
3110
+ }
3111
+ };
3112
+
3113
+ CSSOCompressor.prototype.compressIdentColor = function(token, rule, container) {
3114
+ var map = { 'yellow': 'ff0',
3115
+ 'fuchsia': 'f0f',
3116
+ 'white': 'fff',
3117
+ 'black': '000',
3118
+ 'blue': '00f',
3119
+ 'aqua': '0ff' },
3120
+ allow = { 'value': 1, 'functionBody': 1 },
3121
+ _x = token[2].toLowerCase();
3122
+
3123
+ if (container[1] in allow && _x in map) return [{}, 'vhash', map[_x]];
3124
+ };
3125
+
3126
+ CSSOCompressor.prototype.compressHashColor = function(token) {
3127
+ return this._compressHashColor(token[2], token[0]);
3128
+ };
3129
+
3130
+ CSSOCompressor.prototype._compressHashColor = function(x, info) {
3131
+ var map = { 'f00': 'red',
3132
+ 'c0c0c0': 'silver',
3133
+ '808080': 'gray',
3134
+ '800000': 'maroon',
3135
+ '800080': 'purple',
3136
+ '008000': 'green',
3137
+ '808000': 'olive',
3138
+ '000080': 'navy',
3139
+ '008080': 'teal'},
3140
+ _x = x;
3141
+ x = x.toLowerCase();
3142
+
3143
+ if (x.length === 6 &&
3144
+ x.charAt(0) === x.charAt(1) &&
3145
+ x.charAt(2) === x.charAt(3) &&
3146
+ x.charAt(4) === x.charAt(5)) x = x.charAt(0) + x.charAt(2) + x.charAt(4);
3147
+
3148
+ return map[x] ? [info, 'string', map[x]] : [info, 'vhash', (x.length < _x.length ? x : _x)];
3149
+ };
3150
+
3151
+ CSSOCompressor.prototype.compressFunctionColor = function(token) {
3152
+ var i, v = [], t, h = '', body;
3153
+
3154
+ if (token[2][2] === 'rgb') {
3155
+ body = token[3];
3156
+ for (i = 2; i < body.length; i++) {
3157
+ t = body[i][1];
3158
+ if (t === 'number') v.push(body[i]);
3159
+ else if (t !== 'operator') { v = []; break }
3160
+ }
3161
+ if (v.length === 3) {
3162
+ h += (t = Number(v[0][2]).toString(16)).length === 1 ? '0' + t : t;
3163
+ h += (t = Number(v[1][2]).toString(16)).length === 1 ? '0' + t : t;
3164
+ h += (t = Number(v[2][2]).toString(16)).length === 1 ? '0' + t : t;
3165
+ if (h.length === 6) return this._compressHashColor(h, {});
3166
+ }
3167
+ }
3168
+ };
3169
+
3170
+ CSSOCompressor.prototype.compressDimension = function(token) {
3171
+ var declaration;
3172
+ if (token[2][2] === '0') {
3173
+ if (token[3][2] === 's' && (declaration = this.findDeclaration(token))) {
3174
+ var declName = declaration[2][2][2];
3175
+ if (declName === '-moz-transition') return; // https://github.com/css/csso/issues/82
3176
+ if (declName === '-moz-animation' || declName === 'animation') return; // https://github.com/css/csso/issues/100
3177
+ }
3178
+ return token[2];
3179
+ }
3180
+ };
3181
+
3182
+ CSSOCompressor.prototype.compressString = function(token, rule, container) {
3183
+ var s = token[2], r = '', c;
3184
+ for (var i = 0; i < s.length; i++) {
3185
+ c = s.charAt(i);
3186
+ if (c === '\\' && s.charAt(i + 1) === '\n') i++;
3187
+ else r += c;
3188
+ }
3189
+ // if (container[1] === 'attrib' && /^('|")[a-zA-Z0-9]*('|")$/.test(r)) {
3190
+ // r = r.substring(1, r.length - 1);
3191
+ // }
3192
+ if (s.length !== r.length) return [{}, 'string', r];
3193
+ };
3194
+
3195
+ CSSOCompressor.prototype.compressFontWeight = function(token) {
3196
+ var p = token[2],
3197
+ v = token[3];
3198
+ if (p[2][2].indexOf('font-weight') !== -1 && v[2][1] === 'ident') {
3199
+ if (v[2][2] === 'normal') v[2] = [{}, 'number', '400'];
3200
+ else if (v[2][2] === 'bold') v[2] = [{}, 'number', '700'];
3201
+ return token;
3202
+ }
3203
+ };
3204
+
3205
+ CSSOCompressor.prototype.compressFont = function(token) {
3206
+ var p = token[2],
3207
+ v = token[3],
3208
+ i, x, t;
3209
+ if (/font$/.test(p[2][2]) && v.length) {
3210
+ v.splice(2, 0, [{}, 's', '']);
3211
+ for (i = v.length - 1; i > 2; i--) {
3212
+ x = v[i];
3213
+ if (x[1] === 'ident') {
3214
+ x = x[2];
3215
+ if (x === 'bold') v[i] = [{}, 'number', '700'];
3216
+ else if (x === 'normal') {
3217
+ t = v[i - 1];
3218
+ if (t[1] === 'operator' && t[2] === '/') v.splice(--i, 2);
3219
+ else v.splice(i, 1);
3220
+ if (v[i - 1][1] === 's') v.splice(--i, 1);
3221
+ }
3222
+ else if (x === 'medium' && v[i + 1] && v[i + 1][2] !== '/') {
3223
+ v.splice(i, 1);
3224
+ if (v[i - 1][1] === 's') v.splice(--i, 1);
3225
+ }
3226
+ }
3227
+ }
3228
+ if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
3229
+ if (v.length === 2) v.push([{}, 'ident', 'normal']);
3230
+ return token;
3231
+ }
3232
+ };
3233
+
3234
+ CSSOCompressor.prototype.compressBackground = function(token) {
3235
+ var p = token[2],
3236
+ v = token[3],
3237
+ i, x, t,
3238
+ n = v[v.length - 1][1] === 'important' ? 3 : 2;
3239
+ if (/background$/.test(p[2][2]) && v.length) {
3240
+ v.splice(2, 0, [{}, 's', '']);
3241
+ for (i = v.length - 1; i > n; i--) {
3242
+ x = v[i];
3243
+ if (x[1] === 'ident') {
3244
+ x = x[2];
3245
+ if (x === 'transparent' || x === 'none' || x === 'repeat' || x === 'scroll') {
3246
+ v.splice(i, 1);
3247
+ if (v[i - 1][1] === 's') v.splice(--i, 1);
3248
+ }
3249
+ }
3250
+ }
3251
+ if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
3252
+ if (v.length === 2) v.splice(2, 0, [{}, 'number', '0'], [{}, 's', ' '], [{}, 'number', '0']);
3253
+ return token;
3254
+ }
3255
+ };
3256
+
3257
+ CSSOCompressor.prototype.cleanEmpty = function(token, rule) {
3258
+ switch(rule) {
3259
+ case 'ruleset':
3260
+ if (token[3].length === 2) return null;
3261
+ break;
3262
+ case 'atruleb':
3263
+ if (token[token.length - 1].length < 3) return null;
3264
+ break;
3265
+ case 'atruler':
3266
+ if (token[4].length < 3) return null;
3267
+ break;
3268
+ }
3269
+ };
3270
+
3271
+ CSSOCompressor.prototype.destroyDelims = function() {
3272
+ return null;
3273
+ };
3274
+
3275
+ CSSOCompressor.prototype.preTranslate = function(token) {
3276
+ token[0].s = translator.translate(cleanInfo(token));
3277
+ return token;
3278
+ };
3279
+
3280
+ CSSOCompressor.prototype.markShorthands = function(token, rule, container, j, path) {
3281
+ if (container[1] === 'ruleset') {
3282
+ var selector = container[2][2][0].s,
3283
+ freeze = container[0].freeze,
3284
+ freezeID = container[0].freezeID;
3285
+ } else {
3286
+ var selector = '',
3287
+ freeze = false,
3288
+ freezeID = 'fake';
3289
+ }
3290
+ var x, p, v, imp, s, key, sh,
3291
+ pre = this.pathUp(path) + '/' + (freeze ? '&' + freezeID + '&' : '') + selector + '/',
3292
+ createNew, shortsI, shortGroupID = container[0].shortGroupID;
3293
+
3294
+ for (var i = token.length - 1; i > -1; i--) {
3295
+ createNew = true;
3296
+ x = token[i];
3297
+ if (x[1] === 'declaration') {
3298
+ v = x[3];
3299
+ imp = v[v.length - 1][1] === 'important';
3300
+ p = x[2][0].s;
3301
+ x[0].id = path + '/' + i;
3302
+ if (p in TRBL.props) {
3303
+ key = pre + TRBL.extractMain(p);
3304
+ var shorts = this.shorts2[key] || [];
3305
+ shortsI = shorts.length === 0 ? 0 : shorts.length - 1;
3306
+
3307
+ if (!this.lastShortSelector || selector === this.lastShortSelector || shortGroupID === this.lastShortGroupID) {
3308
+ if (shorts.length) {
3309
+ sh = shorts[shortsI];
3310
+ //if (imp && !sh.imp) sh.invalid = true;
3311
+ createNew = false;
3312
+ }
3313
+ }
3314
+
3315
+ if (createNew) {
3316
+ x[0].replaceByShort = true;
3317
+ x[0].shorthandKey = { key: key, i: shortsI };
3318
+ sh = new TRBL(p, imp);
3319
+ shorts.push(sh);
3320
+ }
3321
+
3322
+ if (!sh.invalid) {
3323
+ x[0].removeByShort = true;
3324
+ x[0].shorthandKey = { key: key, i: shortsI };
3325
+ sh.add(p, v[0].s, v.slice(2), imp);
3326
+ }
3327
+
3328
+ this.shorts2[key] = shorts;
3329
+
3330
+ this.lastShortSelector = selector;
3331
+ this.lastShortGroupID = shortGroupID;
3332
+ }
3333
+ }
3334
+ }
3335
+
3336
+
3337
+ return token;
3338
+ };
3339
+
3340
+ CSSOCompressor.prototype.cleanShorthands = function(token) {
3341
+ if (token[0].removeByShort || token[0].replaceByShort) {
3342
+ var s, t, sKey = token[0].shorthandKey;
3343
+
3344
+ s = this.shorts2[sKey.key][sKey.i];
3345
+
3346
+ if (!s.invalid && s.isOkToMinimize()) {
3347
+ if (token[0].replaceByShort) {
3348
+ t = [{}, 'declaration', s.getProperty(), s.getValue()];
3349
+ t[0].s = translator.translate(cleanInfo(t));
3350
+ return t;
3351
+ } else return null;
3352
+ }
3353
+ }
3354
+ };
3355
+
3356
+ CSSOCompressor.prototype.dontRestructure = {
3357
+ 'src': 1, // https://github.com/afelix/csso/issues/50
3358
+ 'clip': 1, // https://github.com/afelix/csso/issues/57
3359
+ 'display': 1 // https://github.com/afelix/csso/issues/71
3360
+ };
3361
+
3362
+ CSSOCompressor.prototype.restructureBlock = function(token, rule, container, j, path) {
3363
+ if (container[1] === 'ruleset') {
3364
+ var props = this.props,
3365
+ isPseudo = container[2][2][0].pseudo,
3366
+ selector = container[2][2][0].s,
3367
+ freeze = container[0].freeze,
3368
+ freezeID = container[0].freezeID,
3369
+ pseudoID = container[0].pseudoID,
3370
+ sg = container[2][2][0].sg;
3371
+ } else {
3372
+ var props = {},
3373
+ isPseudo = false,
3374
+ selector = '',
3375
+ freeze = false,
3376
+ freezeID = 'fake',
3377
+ pseudoID = 'fake',
3378
+ sg = {};
3379
+ }
3380
+
3381
+ var x, p, v, imp, t,
3382
+ pre = this.pathUp(path) + '/' + selector + '/',
3383
+ ppre;
3384
+
3385
+ for (var i = token.length - 1; i > -1; i--) {
3386
+ x = token[i];
3387
+ if (x[1] === 'declaration') {
3388
+ v = x[3];
3389
+ imp = v[v.length - 1][1] === 'important';
3390
+ p = x[2][0].s;
3391
+ ppre = this.buildPPre(pre, p, v, x, freeze);
3392
+ x[0].id = path + '/' + i;
3393
+ if (!this.dontRestructure[p] && (t = props[ppre])) {
3394
+ if ((isPseudo && freezeID === t.freezeID) || // pseudo from equal selectors group
3395
+ (!isPseudo && pseudoID === t.pseudoID) || // not pseudo from equal pseudo signature group
3396
+ (isPseudo && pseudoID === t.pseudoID && this.hashInHash(sg, t.sg))) { // pseudo from covered selectors group
3397
+ if (imp && !t.imp) {
3398
+ props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
3399
+ freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
3400
+ this.deleteProperty(t.block, t.id);
3401
+ } else {
3402
+ token.splice(i, 1);
3403
+ }
3404
+ }
3405
+ } else if (this.needless(p, props, pre, imp, v, x, freeze)) {
3406
+ token.splice(i, 1);
3407
+ } else {
3408
+ props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
3409
+ freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
3410
+ }
3411
+ }
3412
+ }
3413
+ return token;
3414
+ };
3415
+
3416
+ CSSOCompressor.prototype.buildPPre = function(pre, p, v, d, freeze) {
3417
+ var fp = freeze ? 'ft:' : 'ff:';
3418
+ if (p.indexOf('background') !== -1) return fp + pre + d[0].s;
3419
+
3420
+ var _v = v.slice(2),
3421
+ colorMark = [
3422
+ 0, // ident, vhash, rgb
3423
+ 0, // hsl
3424
+ 0, // hsla
3425
+ 0 // rgba
3426
+ ],
3427
+ vID = '';
3428
+
3429
+ for (var i = 0; i < _v.length; i++) {
3430
+ if (!vID) vID = this.getVendorIDFromToken(_v[i]);
3431
+ switch(_v[i][1]) {
3432
+ case 'vhash':
3433
+ case 'ident':
3434
+ colorMark[0] = 1; break;
3435
+ case 'funktion':
3436
+ switch(_v[i][2][2]) {
3437
+ case 'rgb':
3438
+ colorMark[0] = 1; break;
3439
+ case 'hsl':
3440
+ colorMark[1] = 1; break;
3441
+ case 'hsla':
3442
+ colorMark[2] = 1; break;
3443
+ case 'rgba':
3444
+ colorMark[3] = 1; break;
3445
+ }
3446
+ break;
3447
+ }
3448
+ }
3449
+
3450
+ return fp + pre + p + colorMark.join('') + (vID ? vID : '');
3451
+ };
3452
+
3453
+ CSSOCompressor.prototype.vendorID = {
3454
+ '-o-': 'o',
3455
+ '-moz-': 'm',
3456
+ '-webkit-': 'w',
3457
+ '-ms-': 'i',
3458
+ '-epub-': 'e',
3459
+ '-apple-': 'a',
3460
+ '-xv-': 'x',
3461
+ '-wap-': 'p'
3462
+ };
3463
+
3464
+ CSSOCompressor.prototype.getVendorIDFromToken = function(token) {
3465
+ var vID;
3466
+ switch(token[1]) {
3467
+ case 'ident':
3468
+ if (vID = this.getVendorFromString(token[2])) return this.vendorID[vID];
3469
+ break;
3470
+ case 'funktion':
3471
+ if (vID = this.getVendorFromString(token[2][2])) return this.vendorID[vID];
3472
+ break;
3473
+ }
3474
+ };
3475
+
3476
+ CSSOCompressor.prototype.getVendorFromString = function(string) {
3477
+ var vendor = string.charAt(0), i;
3478
+ if (vendor === '-') {
3479
+ if ((i = string.indexOf('-', 2)) !== -1) return string.substr(0, i + 1);
3480
+ }
3481
+ return '';
3482
+ };
3483
+
3484
+ CSSOCompressor.prototype.deleteProperty = function(block, id) {
3485
+ var d;
3486
+ for (var i = block.length - 1; i > 1; i--) {
3487
+ d = block[i];
3488
+ if (Array.isArray(d) && d[1] === 'declaration' && d[0].id === id) {
3489
+ block.splice(i, 1);
3490
+ return;
3491
+ }
3492
+ }
3493
+ };
3494
+
3495
+ CSSOCompressor.prototype.nlTable = {
3496
+ 'border-width': ['border'],
3497
+ 'border-style': ['border'],
3498
+ 'border-color': ['border'],
3499
+ 'border-top': ['border'],
3500
+ 'border-right': ['border'],
3501
+ 'border-bottom': ['border'],
3502
+ 'border-left': ['border'],
3503
+ 'border-top-width': ['border-top', 'border-width', 'border'],
3504
+ 'border-right-width': ['border-right', 'border-width', 'border'],
3505
+ 'border-bottom-width': ['border-bottom', 'border-width', 'border'],
3506
+ 'border-left-width': ['border-left', 'border-width', 'border'],
3507
+ 'border-top-style': ['border-top', 'border-style', 'border'],
3508
+ 'border-right-style': ['border-right', 'border-style', 'border'],
3509
+ 'border-bottom-style': ['border-bottom', 'border-style', 'border'],
3510
+ 'border-left-style': ['border-left', 'border-style', 'border'],
3511
+ 'border-top-color': ['border-top', 'border-color', 'border'],
3512
+ 'border-right-color': ['border-right', 'border-color', 'border'],
3513
+ 'border-bottom-color': ['border-bottom', 'border-color', 'border'],
3514
+ 'border-left-color': ['border-left', 'border-color', 'border'],
3515
+ 'margin-top': ['margin'],
3516
+ 'margin-right': ['margin'],
3517
+ 'margin-bottom': ['margin'],
3518
+ 'margin-left': ['margin'],
3519
+ 'padding-top': ['padding'],
3520
+ 'padding-right': ['padding'],
3521
+ 'padding-bottom': ['padding'],
3522
+ 'padding-left': ['padding'],
3523
+ 'font-style': ['font'],
3524
+ 'font-variant': ['font'],
3525
+ 'font-weight': ['font'],
3526
+ 'font-size': ['font'],
3527
+ 'font-family': ['font'],
3528
+ 'list-style-type': ['list-style'],
3529
+ 'list-style-position': ['list-style'],
3530
+ 'list-style-image': ['list-style']
3531
+ };
3532
+
3533
+ CSSOCompressor.prototype.needless = function(name, props, pre, imp, v, d, freeze) {
3534
+ var hack = name.charAt(0);
3535
+ if (hack === '*' || hack === '_' || hack === '$') name = name.substr(1);
3536
+ else if (hack === '/' && name.charAt(1) === '/') {
3537
+ hack = '//';
3538
+ name = name.substr(2);
3539
+ } else hack = '';
3540
+
3541
+ var vendor = this.getVendorFromString(name),
3542
+ prop = name.substr(vendor.length),
3543
+ x, t, ppre;
3544
+
3545
+ if (prop in this.nlTable) {
3546
+ x = this.nlTable[prop];
3547
+ for (var i = 0; i < x.length; i++) {
3548
+ ppre = this.buildPPre(pre, hack + vendor + x[i], v, d, freeze);
3549
+ if (t = props[ppre]) return (!imp || t.imp);
3550
+ }
3551
+ }
3552
+ };
3553
+
3554
+ CSSOCompressor.prototype.rejoinRuleset = function(token, rule, container, i) {
3555
+ var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
3556
+ ps = p ? p[2].slice(2) : [],
3557
+ pb = p ? p[3].slice(2) : [],
3558
+ ts = token[2].slice(2),
3559
+ tb = token[3].slice(2),
3560
+ ph, th, r;
3561
+
3562
+ if (!tb.length) return null;
3563
+
3564
+ if (ps.length && pb.length) {
3565
+ if (token[1] !== p[1]) return;
3566
+ // try to join by selectors
3567
+ ph = this.getHash(ps);
3568
+ th = this.getHash(ts);
3569
+
3570
+ if (this.equalHash(th, ph)) {
3571
+ p[3] = p[3].concat(token[3].splice(2));
3572
+ return null;
3573
+ }
3574
+ if (this.okToJoinByProperties(token, p)) {
3575
+ // try to join by properties
3576
+ r = this.analyze(token, p);
3577
+ if (!r.ne1.length && !r.ne2.length) {
3578
+ p[2] = this.cleanSelector(p[2].concat(token[2].splice(2)));
3579
+ p[2][0].s = translator.translate(cleanInfo(p[2]));
3580
+ return null;
3581
+ }
3582
+ }
3583
+ }
3584
+ };
3585
+
3586
+ CSSOCompressor.prototype.okToJoinByProperties = function(r0, r1) {
3587
+ var i0 = r0[0], i1 = r1[0];
3588
+
3589
+ // same frozen ruleset
3590
+ if (i0.freezeID === i1.freezeID) return true;
3591
+
3592
+ // same pseudo-classes in selectors
3593
+ if (i0.pseudoID === i1.pseudoID) return true;
3594
+
3595
+ // different frozen rulesets
3596
+ if (i0.freeze && i1.freeze) {
3597
+ return this.pseudoSelectorSignature(r0[2], this.allowedPClasses) === this.pseudoSelectorSignature(r1[2], this.allowedPClasses);
3598
+ }
3599
+
3600
+ // is it frozen at all?
3601
+ return !(i0.freeze || i1.freeze);
3602
+ };
3603
+
3604
+ CSSOCompressor.prototype.allowedPClasses = {
3605
+ 'after': 1,
3606
+ 'before': 1
3607
+ };
3608
+
3609
+ CSSOCompressor.prototype.containsOnlyAllowedPClasses = function(selector) {
3610
+ var ss;
3611
+ for (var i = 2; i < selector.length; i++) {
3612
+ ss = selector[i];
3613
+ for (var j = 2; j < ss.length; j++) {
3614
+ if (ss[j][1] == 'pseudoc' || ss[j][1] == 'pseudoe') {
3615
+ if (!(ss[j][2][2] in this.allowedPClasses)) return false;
3616
+ }
3617
+ }
3618
+ }
3619
+ return true;
3620
+ };
3621
+
3622
+ CSSOCompressor.prototype.restructureRuleset = function(token, rule, container, i) {
3623
+ var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
3624
+ ps = p ? p[2].slice(2) : [],
3625
+ pb = p ? p[3].slice(2) : [],
3626
+ tb = token[3].slice(2),
3627
+ r, nr;
3628
+
3629
+ if (!tb.length) return null;
3630
+
3631
+ if (ps.length && pb.length) {
3632
+ if (token[1] !== p[1]) return;
3633
+ // try to join by properties
3634
+ r = this.analyze(token, p);
3635
+
3636
+ if (r.eq.length && (r.ne1.length || r.ne2.length)) {
3637
+ if (r.ne1.length && !r.ne2.length) { // p in token
3638
+ var ns = token[2].slice(2), // TODO: copypaste
3639
+ nss = translator.translate(cleanInfo(token[2])),
3640
+ sl = nss.length + // selector length
3641
+ ns.length - 1, // delims length
3642
+ bl = this.calcLength(r.eq) + // declarations length
3643
+ r.eq.length - 1; // decldelims length
3644
+ if (sl < bl) {
3645
+ p[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
3646
+ token[3].splice(2);
3647
+ token[3] = token[3].concat(r.ne1);
3648
+ return token;
3649
+ }
3650
+ } else if (r.ne2.length && !r.ne1.length) { // token in p
3651
+ var ns = p[2].slice(2),
3652
+ nss = translator.translate(cleanInfo(p[2])),
3653
+ sl = nss.length + // selector length
3654
+ ns.length - 1, // delims length
3655
+ bl = this.calcLength(r.eq) + // declarations length
3656
+ r.eq.length - 1; // decldelims length
3657
+ if (sl < bl) {
3658
+ token[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
3659
+ p[3].splice(2);
3660
+ p[3] = p[3].concat(r.ne2);
3661
+ return token;
3662
+ }
3663
+ } else { // extract equal block?
3664
+ var ns = this.cleanSelector(p[2].concat(token[2].slice(2))),
3665
+ nss = translator.translate(cleanInfo(ns)),
3666
+ rl = nss.length + // selector length
3667
+ ns.length - 1 + // delims length
3668
+ 2, // braces length
3669
+ bl = this.calcLength(r.eq) + // declarations length
3670
+ r.eq.length - 1; // decldelims length
3671
+
3672
+ if (bl >= rl) { // ok, it's good enough to extract
3673
+ ns[0].s = nss;
3674
+ nr = [{f:0, l:0}, 'ruleset', ns, [{f:0,l:0}, 'block'].concat(r.eq)];
3675
+ token[3].splice(2);
3676
+ token[3] = token[3].concat(r.ne1);
3677
+ p[3].splice(2);
3678
+ p[3] = p[3].concat(r.ne2);
3679
+ container.splice(i, 0, nr);
3680
+ return nr;
3681
+ }
3682
+ }
3683
+ }
3684
+ }
3685
+ };
3686
+
3687
+ CSSOCompressor.prototype.calcLength = function(tokens) {
3688
+ var r = 0;
3689
+ for (var i = 0; i < tokens.length; i++) r += tokens[i][0].s.length;
3690
+ return r;
3691
+ };
3692
+
3693
+ CSSOCompressor.prototype.cleanSelector = function(token) {
3694
+ if (token.length === 2) return null;
3695
+ var h = {}, s;
3696
+ for (var i = 2; i < token.length; i++) {
3697
+ s = token[i][0].s;
3698
+ if (s in h) token.splice(i, 1), i--;
3699
+ else h[s] = 1;
3700
+ }
3701
+
3702
+ return token;
3703
+ };
3704
+
3705
+ CSSOCompressor.prototype.analyze = function(r1, r2) {
3706
+ var r = { eq: [], ne1: [], ne2: [] };
3707
+
3708
+ if (r1[1] !== r2[1]) return r;
3709
+
3710
+ var b1 = r1[3], b2 = r2[3],
3711
+ d1 = b1.slice(2), d2 = b2.slice(2),
3712
+ h1, h2, i, x;
3713
+
3714
+ h1 = this.getHash(d1);
3715
+ h2 = this.getHash(d2);
3716
+
3717
+ for (i = 0; i < d1.length; i++) {
3718
+ x = d1[i];
3719
+ if (x[0].s in h2) r.eq.push(x);
3720
+ else r.ne1.push(x);
3721
+ }
3722
+
3723
+ for (i = 0; i < d2.length; i++) {
3724
+ x = d2[i];
3725
+ if (!(x[0].s in h1)) r.ne2.push(x);
3726
+ }
3727
+
3728
+ return r;
3729
+ };
3730
+
3731
+ CSSOCompressor.prototype.equalHash = function(h0, h1) {
3732
+ var k;
3733
+ for (k in h0) if (!(k in h1)) return false;
3734
+ for (k in h1) if (!(k in h0)) return false;
3735
+ return true;
3736
+ };
3737
+
3738
+ CSSOCompressor.prototype.getHash = function(tokens) {
3739
+ var r = {};
3740
+ for (var i = 0; i < tokens.length; i++) r[tokens[i][0].s] = 1;
3741
+ return r;
3742
+ };
3743
+
3744
+ CSSOCompressor.prototype.hashInHash = function(h0, h1) {
3745
+ for (var k in h0) if (!(k in h1)) return false;
3746
+ return true;
3747
+ };
3748
+
3749
+ CSSOCompressor.prototype.delimSelectors = function(token) {
3750
+ for (var i = token.length - 1; i > 2; i--) {
3751
+ token.splice(i, 0, [{}, 'delim']);
3752
+ }
3753
+ };
3754
+
3755
+ CSSOCompressor.prototype.delimBlocks = function(token) {
3756
+ for (var i = token.length - 1; i > 2; i--) {
3757
+ token.splice(i, 0, [{}, 'decldelim']);
3758
+ }
3759
+ };
3760
+
3761
+ CSSOCompressor.prototype.copyArray = function(a) {
3762
+ var r = [], t;
3763
+
3764
+ for (var i = 0; i < a.length; i++) {
3765
+ t = a[i];
3766
+ if (Array.isArray(t)) r.push(this.copyArray(t));
3767
+ else if (typeof t === 'object') r.push(this.copyObject(t));
3768
+ else r.push(t);
3769
+ }
3770
+
3771
+ return r;
3772
+ };
3773
+
3774
+ CSSOCompressor.prototype.copyObject = function(o) {
3775
+ var r = {};
3776
+ for (var k in o) r[k] = o[k];
3777
+ return r;
3778
+ };
3779
+
3780
+ CSSOCompressor.prototype.pathUp = function(path) {
3781
+ return path.substr(0, path.lastIndexOf('/'));
3782
+ };
3783
+ function CSSOTranslator() {}
3784
+
3785
+ CSSOTranslator.prototype.translate = function(tree) {
3786
+ // console.trace('--------');
3787
+ // console.log(tree);
3788
+ return this._t(tree);
3789
+ };
3790
+
3791
+ CSSOTranslator.prototype._m_simple = {
3792
+ 'unary': 1, 'nth': 1, 'combinator': 1, 'ident': 1, 'number': 1, 's': 1,
3793
+ 'string': 1, 'attrselector': 1, 'operator': 1, 'raw': 1, 'unknown': 1
3794
+ };
3795
+
3796
+ CSSOTranslator.prototype._m_composite = {
3797
+ 'simpleselector': 1, 'dimension': 1, 'selector': 1, 'property': 1, 'value': 1,
3798
+ 'filterv': 1, 'progid': 1, 'ruleset': 1, 'atruleb': 1, 'atrulerq': 1, 'atrulers': 1,
3799
+ 'stylesheet': 1
3800
+ };
3801
+
3802
+ CSSOTranslator.prototype._m_primitive = {
3803
+ 'cdo': 'cdo', 'cdc': 'cdc', 'decldelim': ';', 'namespace': '|', 'delim': ','
3804
+ };
3805
+
3806
+ CSSOTranslator.prototype._t = function(tree) {
3807
+ var t = tree[0];
3808
+ if (t in this._m_primitive) return this._m_primitive[t];
3809
+ else if (t in this._m_simple) return this._simple(tree);
3810
+ else if (t in this._m_composite) return this._composite(tree);
3811
+ return this[t](tree);
3812
+ };
3813
+
3814
+ CSSOTranslator.prototype._composite = function(t, i) {
3815
+ var s = '';
3816
+ i = i === undefined ? 1 : i;
3817
+ for (; i < t.length; i++) s += this._t(t[i]);
3818
+ return s;
3819
+ };
3820
+
3821
+ CSSOTranslator.prototype._simple = function(t) {
3822
+ return t[1];
3823
+ };
3824
+
3825
+ CSSOTranslator.prototype.percentage = function(t) {
3826
+ return this._t(t[1]) + '%';
3827
+ };
3828
+
3829
+ CSSOTranslator.prototype.comment = function(t) {
3830
+ return '/*' + t[1] + '*/';
3831
+ };
3832
+
3833
+ CSSOTranslator.prototype.clazz = function(t) {
3834
+ return '.' + this._t(t[1]);
3835
+ };
3836
+
3837
+ CSSOTranslator.prototype.atkeyword = function(t) {
3838
+ return '@' + this._t(t[1]);
3839
+ };
3840
+
3841
+ CSSOTranslator.prototype.shash = function(t) {
3842
+ return '#' + t[1];
3843
+ };
3844
+
3845
+ CSSOTranslator.prototype.vhash = function(t) {
3846
+ return '#' + t[1];
3847
+ };
3848
+
3849
+ CSSOTranslator.prototype.attrib = function(t) {
3850
+ return '[' + this._composite(t) + ']';
3851
+ };
3852
+
3853
+ CSSOTranslator.prototype.important = function(t) {
3854
+ return '!' + this._composite(t) + 'important';
3855
+ };
3856
+
3857
+ CSSOTranslator.prototype.nthselector = function(t) {
3858
+ return ':' + this._simple(t[1]) + '(' + this._composite(t, 2) + ')';
3859
+ };
3860
+
3861
+ CSSOTranslator.prototype.funktion = function(t) {
3862
+ return this._simple(t[1]) + '(' + this._composite(t[2]) + ')';
3863
+ };
3864
+
3865
+ CSSOTranslator.prototype.declaration = function(t) {
3866
+ return this._t(t[1]) + ':' + this._t(t[2]);
3867
+ };
3868
+
3869
+ CSSOTranslator.prototype.filter = function(t) {
3870
+ return this._t(t[1]) + ':' + this._t(t[2]);
3871
+ };
3872
+
3873
+ CSSOTranslator.prototype.block = function(t) {
3874
+ return '{' + this._composite(t) + '}';
3875
+ };
3876
+
3877
+ CSSOTranslator.prototype.braces = function(t) {
3878
+ return t[1] + this._composite(t, 3) + t[2];
3879
+ };
3880
+
3881
+ CSSOTranslator.prototype.atrules = function(t) {
3882
+ return this._composite(t) + ';';
3883
+ };
3884
+
3885
+ CSSOTranslator.prototype.atruler = function(t) {
3886
+ return this._t(t[1]) + this._t(t[2]) + '{' + this._t(t[3]) + '}';
3887
+ };
3888
+
3889
+ CSSOTranslator.prototype.pseudoe = function(t) {
3890
+ return '::' + this._t(t[1]);
3891
+ };
3892
+
3893
+ CSSOTranslator.prototype.pseudoc = function(t) {
3894
+ return ':' + this._t(t[1]);
3895
+ };
3896
+
3897
+ CSSOTranslator.prototype.uri = function(t) {
3898
+ return 'url(' + this._composite(t) + ')';
3899
+ };
3900
+
3901
+ CSSOTranslator.prototype.functionExpression = function(t) {
3902
+ return 'expression(' + t[1] + ')';
3903
+ };
3904
+
3905
+ do_compression = function(css, disable_structural){
3906
+ var compressor = new CSSOCompressor(), translator = new CSSOTranslator();
3907
+ return translator.translate(
3908
+ cleanInfo(
3909
+ compressor.compress(
3910
+ srcToCSSP(css, 'stylesheet', true),
3911
+ disable_structural
3912
+ )
3913
+ )
3914
+ );
3915
+ };