haml-edge 2.3.193 → 2.3.194

Sign up to get free protection for your applications and to get access to all the features.
data/EDGE_GEM_VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.193
1
+ 2.3.194
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.193
1
+ 2.3.194
data/lib/sass/engine.rb CHANGED
@@ -6,7 +6,6 @@ require 'sass/tree/rule_node'
6
6
  require 'sass/tree/comment_node'
7
7
  require 'sass/tree/prop_node'
8
8
  require 'sass/tree/directive_node'
9
- require 'sass/tree/raw_node'
10
9
  require 'sass/tree/variable_node'
11
10
  require 'sass/tree/mixin_def_node'
12
11
  require 'sass/tree/mixin_node'
@@ -462,10 +461,13 @@ WARNING
462
461
 
463
462
  # If value begins with url( or ",
464
463
  # it's a CSS @import rule and we don't want to touch it.
465
- if directive == "import" && value !~ /^(url\(|")/
464
+ if directive == "import" && value !~ /^(url\(|["'])/
466
465
  raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
467
466
  :line => @line + 1) unless line.children.empty?
468
- value.split(/,\s*/).map {|f| Tree::ImportNode.new(f)}
467
+ value.split(/,\s*/).map do |f|
468
+ f = $1 || $2 || $3 if f =~ Sass::SCSS::RX::STRING || f =~ Sass::SCSS::RX::URI
469
+ Tree::ImportNode.new(f)
470
+ end
469
471
  elsif directive == "mixin"
470
472
  parse_mixin_definition(line)
471
473
  elsif directive == "include"
@@ -486,10 +488,6 @@ WARNING
486
488
  :line => @line + 1) unless line.children.empty?
487
489
  offset = line.offset + line.text.index(value).to_i
488
490
  Tree::DebugNode.new(parse_script(value, :offset => offset))
489
- elsif directive == "raw"
490
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath raw directives.",
491
- :line => @line + 1) unless line.children.empty?
492
- Tree::RawNode.new(value)
493
491
  else
494
492
  Tree::DirectiveNode.new(line.text)
495
493
  end
@@ -7,10 +7,7 @@ module Sass
7
7
 
8
8
  def string(*args)
9
9
  return unless scan(STRING)
10
- str = (@scanner[1] || @scanner[2]).
11
- gsub(/\\([^0-9a-f])/, '\1').
12
- gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1")
13
- [:string, Script::String.new(str, :string)]
10
+ [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
14
11
  end
15
12
 
16
13
  def important
@@ -237,13 +237,13 @@ module Sass
237
237
 
238
238
  def ident
239
239
  return unless s = scan(REGULAR_EXPRESSIONS[:ident])
240
- [:ident, s.gsub(/\\(.)/, '\1')]
240
+ [:ident, s]
241
241
  end
242
242
 
243
243
  def string(re, open)
244
244
  return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
245
245
  @interpolation_stack << re if @scanner[2].empty? # Started an interpolated section
246
- [:string, Script::String.new(@scanner[1].gsub(/\\([^0-9a-f])/, '\1').gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1"), :string)]
246
+ [:string, Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)]
247
247
  end
248
248
 
249
249
  def number
@@ -55,8 +55,6 @@ module Sass::Script
55
55
  return self.value
56
56
  end
57
57
 
58
- # Replace single backslashes with double. Really.
59
- value = self.value.gsub("\\", "\\\\\\\\")
60
58
  return "\"#{value.gsub('"', "\\\"")}\"" if opts[:quote] == %q{"}
61
59
  return "'#{value.gsub("'", "\\'")}'" if opts[:quote] == %q{'}
62
60
  return "\"#{value}\"" unless value.include?('"')
@@ -11,10 +11,31 @@ module Sass::Script
11
11
  end
12
12
 
13
13
  def to_sass(opts = {})
14
+ # We can get rid of all of this when we remove the deprecated :equals context
15
+ before_unquote, before_quote_char, before_str = parse_str(@before.to_sass(opts))
16
+ after_unquote, after_quote_char, after_str = parse_str(@after.to_sass(opts))
17
+ unquote = before_unquote || after_unquote ||
18
+ (before_quote_char && !after_quote_char && !after_str.empty?) ||
19
+ (!before_quote_char && after_quote_char && !before_str.empty?)
20
+ quote_char =
21
+ if before_quote_char && after_quote_char && before_quote_char != after_quote_char
22
+ before_str.gsub!("\\'", "'")
23
+ before_str.gsub!('"', "\\\"")
24
+ after_str.gsub!("\\'", "'")
25
+ after_str.gsub!('"', "\\\"")
26
+ '"'
27
+ else
28
+ before_quote_char || after_quote_char
29
+ end
30
+
14
31
  res = ""
15
- res << @before.to_sass(opts)[0...-1]
32
+ res << 'unquote(' if unquote
33
+ res << quote_char if quote_char
34
+ res << before_str
16
35
  res << '#{' << @mid.to_sass(opts) << '}'
17
- res << @after.to_sass(opts)[1..-1]
36
+ res << after_str
37
+ res << quote_char if quote_char
38
+ res << ')' if unquote
18
39
  res
19
40
  end
20
41
 
@@ -32,5 +53,18 @@ module Sass::Script
32
53
  res << @after.perform(environment).value
33
54
  Sass::Script::String.new(res, :string)
34
55
  end
56
+
57
+ def parse_str(str)
58
+ case str
59
+ when /^unquote\((["'])(.*)\1\)$/
60
+ return true, $1, $2
61
+ when '""'
62
+ return false, nil, ""
63
+ when /^(["'])(.*)\1$/
64
+ return false, $1, $2
65
+ else
66
+ return false, nil, str
67
+ end
68
+ end
35
69
  end
36
70
  end
@@ -276,13 +276,6 @@ module Sass
276
276
  node.has_children = true
277
277
  tok!(/\{/)
278
278
  block_contents(node, context)
279
-
280
- # Support the hack of having # after all properties.
281
- if context == :ruleset && tok(/#/)
282
- node << Sass::Tree::RawNode.new("#")
283
- ss
284
- end
285
-
286
279
  tok!(/\}/)
287
280
  node
288
281
  end
@@ -383,10 +376,8 @@ module Sass
383
376
  ['.', expr!(:interp_ident)]
384
377
  end
385
378
 
386
- # @private
387
- ID_START = /#(?=#{NMCHAR})/
388
379
  def id_selector
389
- return unless tok(ID_START)
380
+ return unless tok(/#(?!\{)/)
390
381
  @expected = "id name"
391
382
  ['#', expr!(:interp_name)]
392
383
  end
@@ -463,8 +454,8 @@ module Sass
463
454
 
464
455
  def declaration
465
456
  # This allows the "*prop: val", ":prop: val", and ".prop: val" hacks
466
- if s = tok(/[:\*\.]/)
467
- @use_property_exception = s != '.'
457
+ if s = tok(/[:\*\.]|\#(?!\{)/)
458
+ @use_property_exception = s !~ /[\.\#]/
468
459
  name = [s, str{ss}, *expr!(:interp_ident)]
469
460
  else
470
461
  return unless name = interp_ident
@@ -665,15 +656,6 @@ MESSAGE
665
656
  pos = scanner.pos
666
657
 
667
658
  after = scanner.string[0...pos]
668
- was = scanner.rest.dup
669
-
670
- # We support the foo {a: b; #} hack,
671
- # but we don't want it cluttering our errors.
672
- if after =~ /\#$/ && expected == '"}"'
673
- after.slice!(-1)
674
- was = '#' + was
675
- end
676
-
677
659
  # Get rid of whitespace between pos and the last token,
678
660
  # but only if there's a newline in there
679
661
  after.gsub!(/\s*\n\s*$/, '')
@@ -681,6 +663,7 @@ MESSAGE
681
663
  after.gsub!(/.*\n/, '')
682
664
  after = "..." + after[-15..-1] if after.size > 18
683
665
 
666
+ was = scanner.rest.dup
684
667
  # Get rid of whitespace between pos and the next token,
685
668
  # but only if there's a newline in there
686
669
  was.gsub!(/^\s*\n\s*/, '')
@@ -80,6 +80,10 @@ module Sass::Tree
80
80
 
81
81
  def to_src(tabs, opts, fmt)
82
82
  name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
83
+ if name[0] == ?:
84
+ raise Sass::SyntaxError.new("The \":#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
85
+ end
86
+
83
87
  old = opts[:old] && fmt == :sass
84
88
  initial = old ? ':' : ''
85
89
  mid = old ? '' : ':'
@@ -777,18 +777,71 @@ SCSS
777
777
  assert_sass_to_scss '$var: 12px $bar baz !default;', '$var ||= 12px $bar "baz"'
778
778
  end
779
779
 
780
- def test_hash_hack
780
+ # Hacks
781
+
782
+ def test_declaration_hacks
781
783
  assert_renders <<SASS, <<SCSS
782
784
  foo
783
- bar: baz
784
- @raw #
785
+ _name: val
786
+ *name: val
787
+ #name: val
788
+ .name: val
789
+ name: val
785
790
  SASS
786
791
  foo {
787
- bar: baz;
788
- # }
792
+ _name: val;
793
+ *name: val;
794
+ #name: val;
795
+ .name: val;
796
+ name: val; }
789
797
  SCSS
790
798
  end
791
799
 
800
+ def test_old_declaration_hacks
801
+ assert_renders <<SASS, <<SCSS, :old => true
802
+ foo
803
+ :_name val
804
+ :*name val
805
+ :#name val
806
+ :.name val
807
+ :name val
808
+ SASS
809
+ foo {
810
+ _name: val;
811
+ *name: val;
812
+ #name: val;
813
+ .name: val;
814
+ name: val; }
815
+ SCSS
816
+ end
817
+
818
+ def test_selector_hacks
819
+ assert_selector_renders = lambda do |s|
820
+ assert_renders <<SASS, <<SCSS
821
+ #{s}
822
+ a: b
823
+ SASS
824
+ #{s} {
825
+ a: b; }
826
+ SCSS
827
+ end
828
+
829
+ assert_selector_renders['> E']
830
+ assert_selector_renders['+ E']
831
+ assert_selector_renders['~ E']
832
+ assert_selector_renders['>> E']
833
+
834
+ assert_selector_renders['E*']
835
+ assert_selector_renders['E*.foo']
836
+ assert_selector_renders['E*:hover']
837
+ end
838
+
839
+ def test_disallowed_colon_hack
840
+ assert_raise(Sass::SyntaxError, '":foo: bar" is not allowed in the Sass syntax') do
841
+ to_sass("foo {:name: val;}", :syntax => :scss)
842
+ end
843
+ end
844
+
792
845
  # Sass 3 Deprecation conversions
793
846
 
794
847
  def test_simple_quoted_strings_unquoted_with_equals
@@ -56,7 +56,6 @@ MSG
56
56
  "@import foo.sass" => "File to import not found or unreadable: foo.sass.",
57
57
  "a,\n$b: 1" => ["Rules can\'t end in commas.", 1],
58
58
  "$a: b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
59
- "@raw foo {}\n a: b\n" => "Illegal nesting: Nothing may be nested beneath raw directives.",
60
59
  "@import foo.sass" => <<MSG,
61
60
  File to import not found or unreadable: foo.sass.
62
61
  Load paths:
@@ -590,20 +589,6 @@ END
590
589
  assert_equal("@a{b:c;#d{e:f}g:h}\n", render(to_render, :style => :compressed))
591
590
  end
592
591
 
593
- def test_raw_directive
594
- assert_equal(<<CSS, render(<<SASS))
595
- foo {
596
- bar {
597
- baz: bang;
598
- # }
599
- CSS
600
- @raw foo {
601
- bar
602
- baz: bang
603
- @raw #
604
- SASS
605
- end
606
-
607
592
  def test_line_annotations
608
593
  assert_equal(<<CSS, render(<<SASS, :line_comments => true, :style => :compact))
609
594
  /* line 2, test_line_annotations_inline.sass */
@@ -1906,3 +1891,4 @@ SASS
1906
1891
  Sass::Files.send(:sassc_filename, sassc_path, Sass::Engine::DEFAULT_OPTIONS)
1907
1892
  end
1908
1893
  end
1894
+
@@ -1,7 +1,7 @@
1
- #main { content: Hello!; qstr: 'Quo"ted"!'; hstr: Hyph-en!; width: 30em; background-color: black; color: #ffffaa; short-color: #112233; named-color: olive; con: "foo" bar(9 hi there "boom"); con2: "noquo" quo; }
2
- #main #sidebar { background-color: #00ff98; num-normal: 10; num-dec: 10.2; num-dec0: 99; num-neg: -10; esc: 10 +12; many: 6; order: 7; complex: #4c9db1hi16; }
1
+ #main { content: Hello\!; qstr: 'Quo"ted"!'; hstr: Hyph-en\!; width: 30em; background-color: black; color: #ffffaa; short-color: #112233; named-color: olive; con: "foo" bar(9 hi there "boom"); con2: "noquo" quo; }
2
+ #main #sidebar { background-color: #00ff98; num-normal: 10; num-dec: 10.2; num-dec0: 99; num-neg: -10; esc: 10 \+12; many: 6; order: 7; complex: #4c9db1hi16; }
3
3
 
4
- #plus { num-num: 7; num-num-un: 25em; num-num-un2: 23em; num-num-neg: 9.87; num-str: 100px; num-col: #b7b7b7; num-perc: 31%; str-str: "hi there"; str-str2: "hi there"; str-col: "14em solid #112233"; str-num: "times: 13"; col-num: #ff7b9d; col-col: #5173ff; }
4
+ #plus { num-num: 7; num-num-un: 25em; num-num-un2: 23em; num-num-neg: 9.87; num-str: 100px; num-col: #b7b7b7; num-perc: 31%; str-str: "hi\ there"; str-str2: "hi there"; str-col: "14em solid #112233"; str-num: "times: 13"; col-num: #ff7b9d; col-col: #5173ff; }
5
5
 
6
6
  #minus { num-num: 900; col-num: #f9f9f4; col-col: #000035; unary-num: -1; unary-const: 10; unary-paren: -11; unary-two: 12; unary-many: 12; unary-crazy: -15; }
7
7
 
@@ -11,6 +11,6 @@
11
11
 
12
12
  #mod { num-num: 2; col-col: #0f0e05; col-num: #020001; }
13
13
 
14
- #const { escaped-quote: $foo !bar; default: Hello! !important; }
14
+ #const { escaped-quote: \$foo \!bar; default: Hello\! !important; }
15
15
 
16
16
  #regression { a: 4; }
@@ -161,7 +161,23 @@ RUBY
161
161
  assert_renders '"foo #{$bar} #{$bang} baz"'
162
162
  assert_renders '"#{$bar}baz"'
163
163
  assert_renders '"foo#{$bar}"'
164
- assert_renders '"#{$bar}"'
164
+ assert_equal '#{$bar}', render('"#{$bar}"')
165
+
166
+ assert_equal '"foo#{$bar}baz"', render("'foo\#{$bar}baz'")
167
+ end
168
+
169
+ def test_sass2_string_interpolation
170
+ assert_equal 'foo#{$bar}baz', render('"foo#{$bar}baz"', :context => :equals)
171
+ assert_equal '#{$bar}baz', render('"#{$bar}baz"', :context => :equals)
172
+ assert_equal 'foo#{$bar}', render('"foo#{$bar}"', :context => :equals)
173
+
174
+ assert_equal 'unquote(".foo#{$bar}.bar")', render('".foo#{$bar}.bar"', :context => :equals)
175
+ assert_equal 'unquote(".foo#{$bar}")', render('".foo#{$bar}"', :context => :equals)
176
+ assert_equal 'unquote("#{$bar}.bar")', render('"#{$bar}.bar"', :context => :equals)
177
+
178
+ assert_equal "unquote(\"f'o\#{$bar}b'z\")", render("'f\\'o\#{$bar}b\\'z'", :context => :equals)
179
+ assert_equal "unquote('f\"o\#{$bar}b\"z')", render("'f\\\"o\#{$bar}b\\\"z'", :context => :equals)
180
+ assert_equal "unquote(\"f'o\#{$bar}b\\\"z\")", render("'f\\'o\#{$bar}b\\\"z'", :context => :equals)
165
181
  end
166
182
 
167
183
  private
@@ -172,6 +188,8 @@ RUBY
172
188
 
173
189
  def render(script, options = {})
174
190
  munge_filename(options)
175
- Sass::Script.parse(script, 1, 0, options).to_sass
191
+ node = Sass::Script.parse(script, 1, 0, options)
192
+ node.context = options[:context] if options[:context]
193
+ node.to_sass
176
194
  end
177
195
  end
@@ -25,12 +25,12 @@ class SassScriptTest < Test::Unit::TestCase
25
25
  def test_string_escapes
26
26
  assert_equal "'", resolve("\"'\"")
27
27
  assert_equal '"', resolve("\"\\\"\"")
28
- assert_equal "\\", resolve("\"\\\\\"")
28
+ assert_equal "\\\\", resolve("\"\\\\\"")
29
29
  assert_equal "\\02fa", resolve("\"\\02fa\"")
30
30
 
31
31
  assert_equal "'", resolve("'\\''")
32
32
  assert_equal '"', resolve("'\"'")
33
- assert_equal "\\", resolve("'\\\\'")
33
+ assert_equal "\\\\", resolve("'\\\\'")
34
34
  assert_equal "\\02fa", resolve("'\\02fa'")
35
35
  end
36
36
 
@@ -290,7 +290,7 @@ SASS
290
290
  assert_equal "teal(12)", resolve("teal(12)")
291
291
  assert_equal "tealbang(12)", resolve("tealbang(12)")
292
292
  assert_equal "teal-bang(12)", resolve("teal-bang(12)")
293
- assert_equal "teal+bang(12)", resolve("teal\\+bang(12)")
293
+ assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
294
294
  end
295
295
 
296
296
  def test_interpolation_after_hash
@@ -348,6 +348,7 @@ foo {
348
348
  *name: val;
349
349
  :name: val;
350
350
  .name: val;
351
+ #name: val;
351
352
  name: val; }
352
353
  SCSS
353
354
  end
@@ -356,8 +357,8 @@ SCSS
356
357
  assert_parses <<SCSS
357
358
  foo {
358
359
  foo: bar;
359
- baz: bang;
360
- # }
360
+ #baz: bang;
361
+ #bip: bop; }
361
362
  SCSS
362
363
  end
363
364
 
@@ -399,6 +400,28 @@ foo {
399
400
  SCSS
400
401
  end
401
402
 
403
+ def test_css_string_escapes
404
+ assert_parses <<SCSS
405
+ foo {
406
+ a: "\\foo bar";
407
+ b: "foo\\ bar";
408
+ c: "\\2022 \\0020";
409
+ d: "foo\\\\bar";
410
+ e: "foo\\"'bar"; }
411
+ SCSS
412
+ end
413
+
414
+ def test_css_ident_escapes
415
+ assert_parses <<SCSS
416
+ foo {
417
+ a: \\foo bar;
418
+ b: foo\\ bar;
419
+ c: \\2022 \\0020;
420
+ d: foo\\\\bar;
421
+ e: foo\\"\\'bar; }
422
+ SCSS
423
+ end
424
+
402
425
  ## Directives
403
426
 
404
427
  def test_charset_directive
@@ -789,7 +812,7 @@ SCSS
789
812
 
790
813
  def test_no_nested_rules
791
814
  assert_not_parses('":"', 'foo {bar <err>{a: b}}')
792
- assert_not_parses('"}"', 'foo {<err>#bar {a: b}}')
815
+ assert_not_parses('"}"', 'foo {<err>[bar=baz] {a: b}}')
793
816
  end
794
817
 
795
818
  def test_no_nested_properties
@@ -3,7 +3,7 @@ $preconst: hello
3
3
  =premixin
4
4
  pre-mixin: here
5
5
 
6
- @import importee.sass, scss_importee, basic.sass, basic.css, ../results/complex.css, partial.sass
6
+ @import importee.sass, scss_importee, "basic.sass", basic.css, ../results/complex.css, url(partial.sass)
7
7
 
8
8
  nonimported
9
9
  :myconst $preconst
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml-edge
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.193
4
+ version: 2.3.194
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Weizenbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-04-08 00:00:00 -04:00
13
+ date: 2010-04-09 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -118,7 +118,6 @@ files:
118
118
  - lib/sass/tree/rule_node.rb
119
119
  - lib/sass/tree/variable_node.rb
120
120
  - lib/sass/tree/while_node.rb
121
- - lib/sass/tree/raw_node.rb
122
121
  - lib/sass/tree/root_node.rb
123
122
  - lib/sass/scss/css_parser.rb
124
123
  - lib/sass/scss/parser.rb
@@ -1,33 +0,0 @@
1
- module Sass::Tree
2
- # A static node representing raw CSS.
3
- # This simply renders a string value.
4
- #
5
- # @see Sass::Tree
6
- class RawNode < Node
7
- # The text of the hack.
8
- #
9
- # @return [String]
10
- attr_accessor :value
11
-
12
- # @param value [String] See \{#value}
13
- def initialize(value)
14
- @value = value
15
- super()
16
- end
17
-
18
- protected
19
-
20
- def to_src(tabs, opts, fmt)
21
- return "#{' ' * tabs}#{value}" if fmt == :scss
22
- "#{' ' * tabs}@raw #{value}"
23
- end
24
-
25
- # Returns the value of the node.
26
- #
27
- # @param tabs [Fixnum] The level of indentation for the CSS
28
- # @return [String] The resulting CSS
29
- def _to_s(tabs)
30
- "#{' ' * (tabs - 1)}#{value}"
31
- end
32
- end
33
- end