csso-rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ };