css_parser 1.4.10 → 1.5.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/css_parser/parser.rb +99 -25
- data/lib/css_parser/rule_set.rb +15 -0
- data/lib/css_parser/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 842917dce4f3455e696297fb182f1b1783ac3a5a
|
4
|
+
data.tar.gz: ef48928b85b441a68fe9b10e3947643f90a147ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01d11dfbc01781b5ca23598800f53062211f0d7b06074683720ca11354d85d7ea2e9cb2624bfc97265e6ee89ee3c28edb95d02361512a1407c77bd9c8b54d381
|
7
|
+
data.tar.gz: 194c4de30884cc386108ffee89cd1c0426ce4ae2bcfb467515c3fc1ff19dd387680a19306c7ace0f24854adef85846f0eeeca8a01651602c3e744a38cf72ca61
|
data/lib/css_parser/parser.rb
CHANGED
@@ -36,7 +36,8 @@ module CssParser
|
|
36
36
|
def initialize(options = {})
|
37
37
|
@options = {:absolute_paths => false,
|
38
38
|
:import => true,
|
39
|
-
:io_exceptions => true
|
39
|
+
:io_exceptions => true,
|
40
|
+
:capture_offsets => false}.merge(options)
|
40
41
|
|
41
42
|
# array of RuleSets
|
42
43
|
@rules = []
|
@@ -117,7 +118,7 @@ module CssParser
|
|
117
118
|
options[:media_types] = [options[:media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
|
118
119
|
options[:only_media_types] = [options[:only_media_types]].flatten.collect { |mt| CssParser.sanitize_media_query(mt)}
|
119
120
|
|
120
|
-
block = cleanup_block(block)
|
121
|
+
block = cleanup_block(block, options)
|
121
122
|
|
122
123
|
if options[:base_uri] and @options[:absolute_paths]
|
123
124
|
block = CssParser.convert_uris(block, options[:base_uri])
|
@@ -139,17 +140,22 @@ module CssParser
|
|
139
140
|
|
140
141
|
import_path = import_rule[0].to_s.gsub(/['"]*/, '').strip
|
141
142
|
|
143
|
+
import_options = { :media_types => media_types }
|
144
|
+
import_options[:capture_offsets] = true if options[:capture_offsets]
|
145
|
+
|
142
146
|
if options[:base_uri]
|
143
147
|
import_uri = Addressable::URI.parse(options[:base_uri].to_s) + Addressable::URI.parse(import_path)
|
144
|
-
|
148
|
+
import_options[:base_uri] = options[:base_uri]
|
149
|
+
load_uri!(import_uri, import_options)
|
145
150
|
elsif options[:base_dir]
|
146
|
-
|
151
|
+
import_options[:base_dir] = options[:base_dir]
|
152
|
+
load_file!(import_path, import_options)
|
147
153
|
end
|
148
154
|
end
|
149
155
|
end
|
150
156
|
|
151
157
|
# Remove @import declarations
|
152
|
-
block
|
158
|
+
block = ignore_pattern(block, RE_AT_IMPORT_RULE, options)
|
153
159
|
|
154
160
|
parse_block_into_rule_sets!(block, options)
|
155
161
|
end
|
@@ -162,6 +168,16 @@ module CssParser
|
|
162
168
|
add_rule_set!(rule_set, media_types)
|
163
169
|
end
|
164
170
|
|
171
|
+
# Add a CSS rule by setting the +selectors+, +declarations+, +filename+, +offset+ and +media_types+.
|
172
|
+
#
|
173
|
+
# +filename+ can be a string or uri pointing to the file or url location.
|
174
|
+
# +offset+ should be Range object representing the start and end byte locations where the rule was found in the file.
|
175
|
+
# +media_types+ can be a symbol or an array of symbols.
|
176
|
+
def add_rule_with_offsets!(selectors, declarations, filename, offset, media_types = :all)
|
177
|
+
rule_set = OffsetAwareRuleSet.new(filename, offset, selectors, declarations)
|
178
|
+
add_rule_set!(rule_set, media_types)
|
179
|
+
end
|
180
|
+
|
165
181
|
# Add a CssParser RuleSet object.
|
166
182
|
#
|
167
183
|
# +media_types+ can be a symbol or an array of symbols.
|
@@ -289,9 +305,16 @@ module CssParser
|
|
289
305
|
current_media_query = ''
|
290
306
|
current_declarations = ''
|
291
307
|
|
292
|
-
|
308
|
+
# once we are in a rule, we will use this to store where we started if we are capturing offsets
|
309
|
+
rule_start = nil
|
310
|
+
offset = nil
|
311
|
+
|
312
|
+
block.scan(/(([\\]{2,})|([\\]?[{}\s"])|(.[^\s"{}\\]*))/) do |matches|
|
293
313
|
token = matches[0]
|
294
314
|
|
315
|
+
# save the regex offset so that we know where in the file we are
|
316
|
+
offset = Regexp.last_match.offset(0) if options[:capture_offsets]
|
317
|
+
|
295
318
|
if token =~ /\A"/ # found un-escaped double quote
|
296
319
|
in_string = !in_string
|
297
320
|
end
|
@@ -316,11 +339,18 @@ module CssParser
|
|
316
339
|
in_declarations -= 1
|
317
340
|
|
318
341
|
unless current_declarations.strip.empty?
|
319
|
-
|
342
|
+
if options[:capture_offsets]
|
343
|
+
add_rule_with_offsets!(current_selectors, current_declarations, options[:filename], (rule_start..offset.last), current_media_queries)
|
344
|
+
else
|
345
|
+
add_rule!(current_selectors, current_declarations, current_media_queries)
|
346
|
+
end
|
320
347
|
end
|
321
348
|
|
322
349
|
current_selectors = ''
|
323
350
|
current_declarations = ''
|
351
|
+
|
352
|
+
# restart our search for selectors and declarations
|
353
|
+
rule_start = nil if options[:capture_offsets]
|
324
354
|
end
|
325
355
|
elsif token =~ /@media/i
|
326
356
|
# found '@media', reset current media_types
|
@@ -356,11 +386,14 @@ module CssParser
|
|
356
386
|
end
|
357
387
|
else
|
358
388
|
if token =~ /\{/ and not in_string
|
359
|
-
current_selectors.
|
360
|
-
current_selectors.gsub!(/[\s]*$/, '')
|
389
|
+
current_selectors.strip!
|
361
390
|
in_declarations += 1
|
362
391
|
else
|
392
|
+
# if we are in a selector, add the token to the current selectors
|
363
393
|
current_selectors += token
|
394
|
+
|
395
|
+
# mark this as the beginning of the selector unless we have already marked it
|
396
|
+
rule_start = offset.first if options[:capture_offsets] && rule_start.nil? && token =~ /^[^\s]+$/
|
364
397
|
end
|
365
398
|
end
|
366
399
|
end
|
@@ -368,7 +401,11 @@ module CssParser
|
|
368
401
|
|
369
402
|
# check for unclosed braces
|
370
403
|
if in_declarations > 0
|
371
|
-
|
404
|
+
if options[:capture_offsets]
|
405
|
+
add_rule_with_offsets!(current_selectors, current_declarations, options[:filename], (rule_start..offset.last), current_media_queries)
|
406
|
+
else
|
407
|
+
add_rule!(current_selectors, current_declarations, current_media_queries)
|
408
|
+
end
|
372
409
|
end
|
373
410
|
end
|
374
411
|
|
@@ -381,7 +418,6 @@ module CssParser
|
|
381
418
|
# Deprecated: originally accepted three params: `uri`, `base_uri` and `media_types`
|
382
419
|
def load_uri!(uri, options = {}, deprecated = nil)
|
383
420
|
uri = Addressable::URI.parse(uri) unless uri.respond_to? :scheme
|
384
|
-
#base_uri = nil, media_types = :all, options = {}
|
385
421
|
|
386
422
|
opts = {:base_uri => nil, :media_types => :all}
|
387
423
|
|
@@ -399,6 +435,9 @@ module CssParser
|
|
399
435
|
|
400
436
|
opts[:base_uri] = uri if opts[:base_uri].nil?
|
401
437
|
|
438
|
+
# pass on the uri if we are capturing file offsets
|
439
|
+
opts[:filename] = uri.to_s if opts[:capture_offsets]
|
440
|
+
|
402
441
|
src, = read_remote_file(uri) # skip charset
|
403
442
|
if src
|
404
443
|
add_block!(src, opts)
|
@@ -406,20 +445,40 @@ module CssParser
|
|
406
445
|
end
|
407
446
|
|
408
447
|
# Load a local CSS file.
|
409
|
-
def load_file!(file_name,
|
410
|
-
|
448
|
+
def load_file!(file_name, options = {}, deprecated = nil)
|
449
|
+
opts = {:base_dir => nil, :media_types => :all}
|
450
|
+
|
451
|
+
if options.is_a? Hash
|
452
|
+
opts.merge!(options)
|
453
|
+
else
|
454
|
+
opts[:base_dir] = options if options.is_a? String
|
455
|
+
opts[:media_types] = deprecated if deprecated
|
456
|
+
end
|
457
|
+
|
458
|
+
file_name = File.expand_path(file_name, opts[:base_dir])
|
411
459
|
return unless File.readable?(file_name)
|
412
460
|
return unless circular_reference_check(file_name)
|
413
461
|
|
414
462
|
src = IO.read(file_name)
|
415
|
-
base_dir = File.dirname(file_name)
|
416
463
|
|
417
|
-
|
464
|
+
opts[:filename] = file_name if opts[:capture_offsets]
|
465
|
+
opts[:base_dir] = File.dirname(file_name)
|
466
|
+
|
467
|
+
add_block!(src, opts)
|
418
468
|
end
|
419
469
|
|
420
470
|
# Load a local CSS string.
|
421
|
-
def load_string!(src,
|
422
|
-
|
471
|
+
def load_string!(src, options = {}, deprecated = nil)
|
472
|
+
opts = {:base_dir => nil, :media_types => :all}
|
473
|
+
|
474
|
+
if options.is_a? Hash
|
475
|
+
opts.merge!(options)
|
476
|
+
else
|
477
|
+
opts[:base_dir] = options if options.is_a? String
|
478
|
+
opts[:media_types] = deprecated if deprecated
|
479
|
+
end
|
480
|
+
|
481
|
+
add_block!(src, opts)
|
423
482
|
end
|
424
483
|
|
425
484
|
|
@@ -440,20 +499,31 @@ module CssParser
|
|
440
499
|
end
|
441
500
|
end
|
442
501
|
|
502
|
+
# Remove a pattern from a given string
|
503
|
+
#
|
504
|
+
# Returns a string.
|
505
|
+
def ignore_pattern(css, regex, options)
|
506
|
+
# if we are capturing file offsets, replace the characters with spaces to retail the original positions
|
507
|
+
return css.gsub(regex) { |m| ' ' * m.length } if options[:capture_offsets]
|
508
|
+
|
509
|
+
# otherwise just strip it out
|
510
|
+
css.gsub(regex, '')
|
511
|
+
end
|
512
|
+
|
443
513
|
# Strip comments and clean up blank lines from a block of CSS.
|
444
514
|
#
|
445
515
|
# Returns a string.
|
446
|
-
def cleanup_block(block) # :nodoc:
|
516
|
+
def cleanup_block(block, options = {}) # :nodoc:
|
447
517
|
# Strip CSS comments
|
448
|
-
utf8_block = block.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
449
|
-
utf8_block
|
518
|
+
utf8_block = block.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: ' ')
|
519
|
+
utf8_block = ignore_pattern(utf8_block, STRIP_CSS_COMMENTS_RX, options)
|
450
520
|
|
451
521
|
# Strip HTML comments - they shouldn't really be in here but
|
452
522
|
# some people are just crazy...
|
453
|
-
utf8_block
|
523
|
+
utf8_block = ignore_pattern(utf8_block, STRIP_HTML_COMMENTS_RX, options)
|
454
524
|
|
455
525
|
# Strip lines containing just whitespace
|
456
|
-
utf8_block.gsub!(/^\s+$/, "")
|
526
|
+
utf8_block.gsub!(/^\s+$/, "") unless options[:capture_offsets]
|
457
527
|
|
458
528
|
utf8_block
|
459
529
|
end
|
@@ -483,12 +553,16 @@ module CssParser
|
|
483
553
|
|
484
554
|
src = '', charset = nil
|
485
555
|
|
486
|
-
uri = Addressable::URI.parse(uri.to_s)
|
487
556
|
begin
|
557
|
+
uri = Addressable::URI.parse(uri.to_s)
|
558
|
+
|
488
559
|
if uri.scheme == 'file'
|
489
560
|
# local file
|
490
|
-
|
561
|
+
path = uri.path
|
562
|
+
path.gsub!(/^\//, '') if Gem.win_platform?
|
563
|
+
fh = open(path, 'rb')
|
491
564
|
src = fh.read
|
565
|
+
charset = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
|
492
566
|
fh.close
|
493
567
|
else
|
494
568
|
# remote file
|
@@ -503,7 +577,7 @@ module CssParser
|
|
503
577
|
|
504
578
|
res = http.get(uri.request_uri, {'User-Agent' => USER_AGENT, 'Accept-Encoding' => 'gzip'})
|
505
579
|
src = res.body
|
506
|
-
charset =
|
580
|
+
charset = res.respond_to?(:charset) ? res.encoding : 'utf-8'
|
507
581
|
|
508
582
|
if res.code.to_i >= 400
|
509
583
|
@redirect_count = nil
|
data/lib/css_parser/rule_set.rb
CHANGED
@@ -513,4 +513,19 @@ module CssParser
|
|
513
513
|
@selectors = selectors.split(',').map { |s| s.gsub(/\s+/, ' ').strip }
|
514
514
|
end
|
515
515
|
end
|
516
|
+
|
517
|
+
class OffsetAwareRuleSet < RuleSet
|
518
|
+
|
519
|
+
# File offset range
|
520
|
+
attr_reader :offset
|
521
|
+
|
522
|
+
# the local or remote location
|
523
|
+
attr_accessor :filename
|
524
|
+
|
525
|
+
def initialize(filename, offset, selectors, block, specificity = nil)
|
526
|
+
super(selectors, block, specificity)
|
527
|
+
@offset = offset
|
528
|
+
@filename = filename
|
529
|
+
end
|
530
|
+
end
|
516
531
|
end
|
data/lib/css_parser/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: css_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Dunae
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -51,9 +51,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
51
|
version: '0'
|
52
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
|
-
- - "
|
54
|
+
- - ">"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 1.3.1
|
57
57
|
requirements: []
|
58
58
|
rubyforge_project:
|
59
59
|
rubygems_version: 2.6.8
|