css_parser 1.4.10 → 1.5.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b445faf1396f058086f3ec3654d5ebb4a2d1157
4
- data.tar.gz: 2c8b069bfff50b3e5072ba4912d52aff2ec813ee
3
+ metadata.gz: 842917dce4f3455e696297fb182f1b1783ac3a5a
4
+ data.tar.gz: ef48928b85b441a68fe9b10e3947643f90a147ec
5
5
  SHA512:
6
- metadata.gz: 95c649943ddeb1d61395107986d97d594354654647d13453c41c7cee0d2bffeb6645320e2084a56609131f29721f3f7ddb538ed2c068af43770e48947b1fee40
7
- data.tar.gz: ed26582b08c72abf29c10c8f6a45d28c5d8a12cadbaf9dd3096ff96f719251b0334d73ad68b1cb56fc3e489d184fbe53d3bc7cd24fd595d93e4f76f94b1b6250
6
+ metadata.gz: 01d11dfbc01781b5ca23598800f53062211f0d7b06074683720ca11354d85d7ea2e9cb2624bfc97265e6ee89ee3c28edb95d02361512a1407c77bd9c8b54d381
7
+ data.tar.gz: 194c4de30884cc386108ffee89cd1c0426ce4ae2bcfb467515c3fc1ff19dd387680a19306c7ace0f24854adef85846f0eeeca8a01651602c3e744a38cf72ca61
@@ -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}.merge(options)
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
- load_uri!(import_uri, options[:base_uri], media_types)
148
+ import_options[:base_uri] = options[:base_uri]
149
+ load_uri!(import_uri, import_options)
145
150
  elsif options[:base_dir]
146
- load_file!(import_path, options[:base_dir], media_types)
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.gsub!(RE_AT_IMPORT_RULE, '')
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
- block.scan(/(([\\]{2,})|([\\]?[{}\s"])|(.[^\s"{}\\]*))/).each do |matches|
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
- add_rule!(current_selectors, current_declarations, current_media_queries)
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.gsub!(/^[\s]*/, '')
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
- add_rule!(current_selectors, current_declarations, current_media_queries)
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, base_dir = nil, media_types = :all)
410
- file_name = File.expand_path(file_name, base_dir)
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
- add_block!(src, {:media_types => media_types, :base_dir => base_dir})
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, base_dir = nil, media_types = :all)
422
- add_block!(src, {:media_types => media_types, :base_dir => base_dir})
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.gsub!(STRIP_CSS_COMMENTS_RX, '')
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.gsub!(STRIP_HTML_COMMENTS_RX, '')
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
- fh = open(uri.path, 'rb')
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 = fh.respond_to?(:charset) ? fh.charset : 'utf-8'
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CssParser
2
- VERSION = "1.4.10".freeze
2
+ VERSION = "1.5.0.pre".freeze
3
3
  end
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.10
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-09 00:00:00.000000000 Z
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: '0'
56
+ version: 1.3.1
57
57
  requirements: []
58
58
  rubyforge_project:
59
59
  rubygems_version: 2.6.8