sass 3.4.25 → 3.5.0.pre.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/README.md +1 -1
  4. data/Rakefile +13 -157
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/lib/sass.rb +3 -10
  9. data/lib/sass/cache_stores/filesystem.rb +1 -1
  10. data/lib/sass/css.rb +2 -3
  11. data/lib/sass/engine.rb +46 -32
  12. data/lib/sass/environment.rb +27 -6
  13. data/lib/sass/error.rb +5 -5
  14. data/lib/sass/exec/base.rb +3 -12
  15. data/lib/sass/features.rb +1 -0
  16. data/lib/sass/importers/filesystem.rb +2 -2
  17. data/lib/sass/plugin.rb +1 -1
  18. data/lib/sass/plugin/compiler.rb +21 -51
  19. data/lib/sass/plugin/configuration.rb +1 -1
  20. data/lib/sass/plugin/rack.rb +3 -3
  21. data/lib/sass/plugin/staleness_checker.rb +3 -3
  22. data/lib/sass/railtie.rb +1 -1
  23. data/lib/sass/script.rb +3 -3
  24. data/lib/sass/script/functions.rb +238 -47
  25. data/lib/sass/script/lexer.rb +8 -6
  26. data/lib/sass/script/parser.rb +76 -75
  27. data/lib/sass/script/tree/funcall.rb +35 -30
  28. data/lib/sass/script/tree/list_literal.rb +23 -8
  29. data/lib/sass/script/tree/map_literal.rb +2 -2
  30. data/lib/sass/script/tree/node.rb +2 -10
  31. data/lib/sass/script/tree/operation.rb +16 -50
  32. data/lib/sass/script/value.rb +2 -0
  33. data/lib/sass/script/value/arg_list.rb +1 -1
  34. data/lib/sass/script/value/base.rb +20 -3
  35. data/lib/sass/script/value/callable.rb +25 -0
  36. data/lib/sass/script/value/color.rb +10 -10
  37. data/lib/sass/script/value/function.rb +19 -0
  38. data/lib/sass/script/value/helpers.rb +16 -7
  39. data/lib/sass/script/value/list.rb +33 -12
  40. data/lib/sass/script/value/map.rb +2 -2
  41. data/lib/sass/script/value/number.rb +3 -3
  42. data/lib/sass/script/value/string.rb +12 -5
  43. data/lib/sass/scss/parser.rb +101 -45
  44. data/lib/sass/scss/rx.rb +5 -11
  45. data/lib/sass/scss/static_parser.rb +0 -7
  46. data/lib/sass/selector.rb +4 -0
  47. data/lib/sass/selector/abstract_sequence.rb +5 -5
  48. data/lib/sass/selector/comma_sequence.rb +3 -15
  49. data/lib/sass/selector/pseudo.rb +4 -0
  50. data/lib/sass/selector/sequence.rb +30 -3
  51. data/lib/sass/selector/simple.rb +13 -7
  52. data/lib/sass/selector/simple_sequence.rb +1 -1
  53. data/lib/sass/shared.rb +3 -5
  54. data/lib/sass/source/map.rb +4 -4
  55. data/lib/sass/source/position.rb +4 -4
  56. data/lib/sass/stack.rb +21 -1
  57. data/lib/sass/tree/charset_node.rb +1 -1
  58. data/lib/sass/tree/comment_node.rb +1 -1
  59. data/lib/sass/tree/node.rb +3 -3
  60. data/lib/sass/tree/prop_node.rb +46 -54
  61. data/lib/sass/tree/rule_node.rb +7 -15
  62. data/lib/sass/tree/visitors/check_nesting.rb +1 -1
  63. data/lib/sass/tree/visitors/convert.rb +2 -3
  64. data/lib/sass/tree/visitors/cssize.rb +1 -10
  65. data/lib/sass/tree/visitors/deep_copy.rb +2 -2
  66. data/lib/sass/tree/visitors/perform.rb +23 -12
  67. data/lib/sass/tree/visitors/set_options.rb +1 -1
  68. data/lib/sass/tree/visitors/to_css.rb +46 -12
  69. data/lib/sass/util.rb +16 -321
  70. data/lib/sass/util/multibyte_string_scanner.rb +127 -131
  71. data/lib/sass/util/normalized_map.rb +1 -8
  72. data/lib/sass/version.rb +2 -2
  73. data/test/sass-spec.yml +1 -1
  74. data/test/sass/compiler_test.rb +4 -14
  75. data/test/sass/conversion_test.rb +113 -162
  76. data/test/sass/css2sass_test.rb +17 -19
  77. data/test/sass/css_variable_test.rb +176 -70
  78. data/test/sass/encoding_test.rb +2 -32
  79. data/test/sass/engine_test.rb +114 -65
  80. data/test/sass/extend_test.rb +37 -51
  81. data/test/sass/functions_test.rb +57 -15
  82. data/test/sass/importer_test.rb +2 -2
  83. data/test/sass/more_templates/more1.sass +10 -10
  84. data/test/sass/more_templates/more_import.sass +2 -2
  85. data/test/sass/plugin_test.rb +9 -12
  86. data/test/sass/script_conversion_test.rb +9 -0
  87. data/test/sass/script_test.rb +38 -48
  88. data/test/sass/scss/css_test.rb +5 -19
  89. data/test/sass/scss/scss_test.rb +58 -39
  90. data/test/sass/source_map_test.rb +26 -28
  91. data/test/sass/templates/_partial.sass +1 -1
  92. data/test/sass/templates/basic.sass +10 -10
  93. data/test/sass/templates/bork1.sass +1 -1
  94. data/test/sass/templates/bork5.sass +1 -1
  95. data/test/sass/templates/compact.sass +10 -10
  96. data/test/sass/templates/complex.sass +187 -187
  97. data/test/sass/templates/compressed.sass +10 -10
  98. data/test/sass/templates/expanded.sass +10 -10
  99. data/test/sass/templates/import.sass +2 -2
  100. data/test/sass/templates/importee.sass +3 -3
  101. data/test/sass/templates/mixins.sass +22 -22
  102. data/test/sass/templates/multiline.sass +4 -4
  103. data/test/sass/templates/nested.sass +13 -13
  104. data/test/sass/templates/parent_ref.sass +12 -12
  105. data/test/sass/templates/script.sass +70 -70
  106. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  107. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  108. data/test/sass/templates/subdir/subdir.sass +3 -3
  109. data/test/sass/templates/units.sass +10 -10
  110. data/test/sass/util/multibyte_string_scanner_test.rb +139 -149
  111. data/test/sass/util_test.rb +0 -36
  112. data/test/test_helper.rb +39 -0
  113. metadata +30 -57
  114. data/extra/sass-spec-ref.sh +0 -32
  115. data/lib/sass/deprecation.rb +0 -55
  116. data/lib/sass/script/css_variable_warning.rb +0 -52
  117. data/lib/sass/util/cross_platform_random.rb +0 -19
  118. data/lib/sass/util/ordered_hash.rb +0 -192
  119. data/test/sass/results/import_charset_1_8.css +0 -5
  120. data/test/sass/templates/import_charset_1_8.sass +0 -6
  121. data/vendor/listen/CHANGELOG.md +0 -1
  122. data/vendor/listen/CONTRIBUTING.md +0 -38
  123. data/vendor/listen/Gemfile +0 -20
  124. data/vendor/listen/Guardfile +0 -8
  125. data/vendor/listen/LICENSE +0 -20
  126. data/vendor/listen/README.md +0 -349
  127. data/vendor/listen/Rakefile +0 -5
  128. data/vendor/listen/Vagrantfile +0 -96
  129. data/vendor/listen/lib/listen.rb +0 -54
  130. data/vendor/listen/lib/listen/adapter.rb +0 -327
  131. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
  132. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
  133. data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
  134. data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
  135. data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
  136. data/vendor/listen/lib/listen/directory_record.rb +0 -406
  137. data/vendor/listen/lib/listen/listener.rb +0 -323
  138. data/vendor/listen/lib/listen/turnstile.rb +0 -32
  139. data/vendor/listen/lib/listen/version.rb +0 -3
  140. data/vendor/listen/listen.gemspec +0 -28
  141. data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
  142. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  143. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  144. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  145. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  146. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  147. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
  148. data/vendor/listen/spec/listen/listener_spec.rb +0 -258
  149. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  150. data/vendor/listen/spec/listen_spec.rb +0 -67
  151. data/vendor/listen/spec/spec_helper.rb +0 -25
  152. data/vendor/listen/spec/support/adapter_helper.rb +0 -666
  153. data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
  154. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  155. data/vendor/listen/spec/support/listeners_helper.rb +0 -179
  156. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -144,13 +144,6 @@ MESSAGE
144
144
  ns, name = expr!(:qualified_name)
145
145
  res << ns << '|' if ns
146
146
  res << name << tok!(%r{/})
147
-
148
- location = " of #{@filename}" if @filename
149
- Sass::Util.sass_warn <<MESSAGE
150
- DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
151
- The reference combinator #{res} is deprecated and will be removed in a future release.
152
- MESSAGE
153
-
154
147
  res
155
148
  end
156
149
 
@@ -87,6 +87,10 @@ module Sass
87
87
  @name = name
88
88
  end
89
89
 
90
+ def unique?
91
+ true
92
+ end
93
+
90
94
  # @see Selector#to_s
91
95
  def to_s(opts = {})
92
96
  "#" + @name
@@ -8,7 +8,7 @@ module Sass
8
8
  class AbstractSequence
9
9
  # The line of the Sass template on which this selector was declared.
10
10
  #
11
- # @return [Integer]
11
+ # @return [Fixnum]
12
12
  attr_reader :line
13
13
 
14
14
  # The name of the file in which this selector was declared.
@@ -19,8 +19,8 @@ module Sass
19
19
  # Sets the line of the Sass template on which this selector was declared.
20
20
  # This also sets the line for all child selectors.
21
21
  #
22
- # @param line [Integer]
23
- # @return [Integer]
22
+ # @param line [Fixnum]
23
+ # @return [Fixnum]
24
24
  def line=(line)
25
25
  members.each {|m| m.line = line}
26
26
  @line = line
@@ -42,7 +42,7 @@ module Sass
42
42
  # Subclasses should define `#_hash` rather than overriding this method,
43
43
  # which automatically handles memoizing the result.
44
44
  #
45
- # @return [Integer]
45
+ # @return [Fixnum]
46
46
  def hash
47
47
  @_hash ||= _hash
48
48
  end
@@ -83,7 +83,7 @@ module Sass
83
83
  # The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
84
84
  # number or a range representing possible specificities.
85
85
  #
86
- # @return [Integer, Range]
86
+ # @return [Fixnum, Range]
87
87
  def specificity
88
88
  _specificity(members)
89
89
  end
@@ -2,8 +2,6 @@ module Sass
2
2
  module Selector
3
3
  # A comma-separated sequence of selectors.
4
4
  class CommaSequence < AbstractSequence
5
- @@compound_extend_deprecation = Sass::Deprecation.new
6
-
7
5
  # The comma-separated selector sequences
8
6
  # represented by this class.
9
7
  #
@@ -98,11 +96,8 @@ module Sass
98
96
  # The node that caused this extension.
99
97
  # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
100
98
  # The parent directives containing `extend_node`.
101
- # @param allow_compound_target [Boolean]
102
- # Whether `extendee` is allowed to contain compound selectors.
103
99
  # @raise [Sass::SyntaxError] if this extension is invalid.
104
- def populate_extends(extends, extendee, extend_node = nil, parent_directives = [],
105
- allow_compound_target = false)
100
+ def populate_extends(extends, extendee, extend_node = nil, parent_directives = [])
106
101
  extendee.members.each do |seq|
107
102
  if seq.members.size > 1
108
103
  raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
@@ -116,13 +111,6 @@ module Sass
116
111
  end
117
112
 
118
113
  sel = sseq.members
119
- if !allow_compound_target && sel.length > 1
120
- @@compound_extend_deprecation.warn(sseq.filename, sseq.line, <<WARNING)
121
- Extending a compound selector, #{sseq}, is deprecated and will not be supported in a future release.
122
- See https://github.com/sass/sass/issues/1599 for details.
123
- WARNING
124
- end
125
-
126
114
  members.each do |member|
127
115
  unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
128
116
  raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
@@ -158,8 +146,8 @@ WARNING
158
146
  Sass::Script::Value::List.new(seq.members.map do |component|
159
147
  next if component == "\n"
160
148
  Sass::Script::Value::String.new(component.to_s)
161
- end.compact, :space)
162
- end, :comma)
149
+ end.compact, separator: :space)
150
+ end, separator: :comma)
163
151
  end
164
152
 
165
153
  # Returns a string representation of the sequence.
@@ -48,6 +48,10 @@ module Sass
48
48
  @selector = selector
49
49
  end
50
50
 
51
+ def unique?
52
+ type == :class && normalized_name == 'root'
53
+ end
54
+
51
55
  # Returns a copy of this with \{#selector} set to \{#new\_selector}.
52
56
  #
53
57
  # @param new_selector [CommaSequence]
@@ -6,8 +6,8 @@ module Sass
6
6
  # Sets the line of the Sass template on which this selector was declared.
7
7
  # This also sets the line for all child selectors.
8
8
  #
9
- # @param line [Integer]
10
- # @return [Integer]
9
+ # @param line [Fixnum]
10
+ # @return [Fixnum]
11
11
  def line=(line)
12
12
  members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
13
13
  @line = line
@@ -283,6 +283,9 @@ module Sass
283
283
  next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
284
284
  next s2 if parent_superselector?(s1, s2)
285
285
  next s1 if parent_superselector?(s2, s1)
286
+ next unless must_unify?(s1, s2)
287
+ next unless (unified = Sequence.new(s1).unify(Sequence.new(s2)))
288
+ unified.members.first.members if unified.members.length == 1
286
289
  end
287
290
 
288
291
  diff = [[init]]
@@ -494,7 +497,7 @@ module Sass
494
497
  return if seq1.size > seq2.size
495
498
  return seq1.first.superselector?(seq2.last, seq2[0...-1]) if seq1.size == 1
496
499
 
497
- _, si = Sass::Util.enum_with_index(seq2).find do |e, i|
500
+ _, si = seq2.each_with_index.find do |e, i|
498
501
  return if i == seq2.size - 1
499
502
  next if e.is_a?(String)
500
503
  seq1.first.superselector?(e, seq2[0...i])
@@ -537,6 +540,30 @@ module Sass
537
540
  _superselector?(seq1 + [base], seq2 + [base])
538
541
  end
539
542
 
543
+ # Returns whether two selectors must be unified to produce a valid
544
+ # combined selector. This is true when both selectors contain the same
545
+ # unique simple selector such as an id.
546
+ #
547
+ # @param seq1 [Array<SimpleSequence or String>]
548
+ # @param seq2 [Array<SimpleSequence or String>]
549
+ # @return [Boolean]
550
+ def must_unify?(seq1, seq2)
551
+ unique_selectors = seq1.map do |sseq|
552
+ next [] if sseq.is_a?(String)
553
+ sseq.members.select {|sel| sel.unique?}
554
+ end.flatten.to_set
555
+
556
+ return false if unique_selectors.empty?
557
+
558
+ seq2.any? do |sseq|
559
+ next false if sseq.is_a?(String)
560
+ sseq.members.any? do |sel|
561
+ next unless sel.unique?
562
+ unique_selectors.include?(sel)
563
+ end
564
+ end
565
+ end
566
+
540
567
  # Removes redundant selectors from between multiple lists of
541
568
  # selectors. This takes a list of lists of selector sequences;
542
569
  # each individual list is assumed to have no redundancy within
@@ -5,7 +5,7 @@ module Sass
5
5
  class Simple
6
6
  # The line of the Sass template on which this selector was declared.
7
7
  #
8
- # @return [Integer]
8
+ # @return [Fixnum]
9
9
  attr_accessor :line
10
10
 
11
11
  # The name of the file in which this selector was declared,
@@ -14,6 +14,14 @@ module Sass
14
14
  # @return [String, nil]
15
15
  attr_accessor :filename
16
16
 
17
+ # Whether only one instance of this simple selector is allowed in a given
18
+ # complex selector.
19
+ #
20
+ # @return [Boolean]
21
+ def unique?
22
+ false
23
+ end
24
+
17
25
  # @see #to_s
18
26
  #
19
27
  # @return [String]
@@ -36,7 +44,7 @@ module Sass
36
44
  # so if that contains information irrelevant to the identity of the selector,
37
45
  # this should be overridden.
38
46
  #
39
- # @return [Integer]
47
+ # @return [Fixnum]
40
48
  def hash
41
49
  @_hash ||= equality_key.hash
42
50
  end
@@ -72,11 +80,9 @@ module Sass
72
80
  # by the time extension and unification happen,
73
81
  # this exception will only ever be raised as a result of programmer error
74
82
  def unify(sels)
75
- return sels.first.unify([self]) if sels.length == 1 && sels.first.is_a?(Universal)
76
83
  return sels if sels.any? {|sel2| eql?(sel2)}
77
- sels_with_ix = Sass::Util.enum_with_index(sels)
78
84
  if !is_a?(Pseudo) || (sels.last.is_a?(Pseudo) && sels.last.type == :element)
79
- _, i = sels_with_ix.find {|sel, _| sel.is_a?(Pseudo)}
85
+ _, i = sels.each_with_index.find {|sel, _| sel.is_a?(Pseudo)}
80
86
  end
81
87
  return sels + [self] unless i
82
88
  sels[0...i] + [self] + sels[i..-1]
@@ -107,10 +113,10 @@ module Sass
107
113
  # could be found at all.
108
114
  # If the second value is `false`, the first should be ignored.
109
115
  def unify_namespaces(ns1, ns2)
116
+ return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == '*' || ns2.nil? || ns2 == '*'
110
117
  return ns2, true if ns1 == '*'
111
118
  return ns1, true if ns2 == '*'
112
- return nil, false unless ns1 == ns2
113
- [ns1, true]
119
+ [ns1 || ns2, true]
114
120
  end
115
121
  end
116
122
  end
@@ -184,7 +184,7 @@ module Sass
184
184
  result
185
185
  end.flatten
186
186
 
187
- groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
187
+ groups = extends[members.to_set].group_by {|ex| ex.extender}.to_a
188
188
  groups.map! do |seq, group|
189
189
  sels = group.map {|e| e.target}.flatten
190
190
  # If A {@extend B} and C {...},
@@ -27,11 +27,9 @@ module Sass
27
27
  # from to
28
28
  #
29
29
  # @param scanner [StringScanner] The string scanner to move
30
- # @param start [Character] The character opening the balanced pair.
31
- # A `Fixnum` in 1.8, a `String` in 1.9
32
- # @param finish [Character] The character closing the balanced pair.
33
- # A `Fixnum` in 1.8, a `String` in 1.9
34
- # @param count [Integer] The number of opening characters matched
30
+ # @param start [String] The character opening the balanced pair.
31
+ # @param finish [String] The character closing the balanced pair.
32
+ # @param count [Fixnum] The number of opening characters matched
35
33
  # before calling this method
36
34
  # @return [(String, String)] The string matched within the balanced pair
37
35
  # and the rest of the string.
@@ -37,7 +37,7 @@ module Sass::Source
37
37
 
38
38
  # Shifts all output source ranges forward one or more lines.
39
39
  #
40
- # @param delta [Integer] The number of lines to shift the ranges forward.
40
+ # @param delta [Fixnum] The number of lines to shift the ranges forward.
41
41
  def shift_output_lines(delta)
42
42
  return if delta == 0
43
43
  @data.each do |m|
@@ -49,7 +49,7 @@ module Sass::Source
49
49
  # Shifts any output source ranges that lie on the first line forward one or
50
50
  # more characters on that line.
51
51
  #
52
- # @param delta [Integer] The number of characters to shift the ranges
52
+ # @param delta [Fixnum] The number of characters to shift the ranges
53
53
  # forward.
54
54
  def shift_output_offsets(delta)
55
55
  return if delta == 0
@@ -93,8 +93,8 @@ module Sass::Source
93
93
  raise ArgumentError.new("Sass::Source::Map#to_json requires either " \
94
94
  "the :css_uri option or both the :css_path and :soucemap_path options.")
95
95
  end
96
- css_path &&= Sass::Util.pathname(Sass::Util.absolute_path(css_path))
97
- sourcemap_path &&= Sass::Util.pathname(Sass::Util.absolute_path(sourcemap_path))
96
+ css_path &&= Sass::Util.pathname(File.absolute_path(css_path))
97
+ sourcemap_path &&= Sass::Util.pathname(File.absolute_path(sourcemap_path))
98
98
  css_uri ||= Sass::Util.file_uri_from_path(
99
99
  Sass::Util.relative_path_from(css_path, sourcemap_path.dirname))
100
100
 
@@ -2,17 +2,17 @@ module Sass::Source
2
2
  class Position
3
3
  # The one-based line of the document associated with the position.
4
4
  #
5
- # @return [Integer]
5
+ # @return [Fixnum]
6
6
  attr_accessor :line
7
7
 
8
8
  # The one-based offset in the line of the document associated with the
9
9
  # position.
10
10
  #
11
- # @return [Integer]
11
+ # @return [Fixnum]
12
12
  attr_accessor :offset
13
13
 
14
- # @param line [Integer] The source line
15
- # @param offset [Integer] The source offset
14
+ # @param line [Fixnum] The source line
15
+ # @param offset [Fixnum] The source offset
16
16
  def initialize(line, offset)
17
17
  @line = line
18
18
  @offset = offset
@@ -98,8 +98,28 @@ module Sass
98
98
  with_frame(filename, line, :mixin, name) {yield}
99
99
  end
100
100
 
101
+ # Pushes a function frame onto the stack.
102
+ #
103
+ # @param filename [String] See \{Frame#filename}.
104
+ # @param line [String] See \{Frame#line}.
105
+ # @param name [String] See \{Frame#name}.
106
+ # @yield [] A block in which the new frame is on the stack.
107
+ def with_function(filename, line, name)
108
+ with_frame(filename, line, :function, name) {yield}
109
+ end
110
+
111
+ # Pushes a function frame onto the stack.
112
+ #
113
+ # @param filename [String] See \{Frame#filename}.
114
+ # @param line [String] See \{Frame#line}.
115
+ # @param name [String] See \{Frame#name}.
116
+ # @yield [] A block in which the new frame is on the stack.
117
+ def with_directive(filename, line, name)
118
+ with_frame(filename, line, :directive, name) {yield}
119
+ end
120
+
101
121
  def to_s
102
- Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
122
+ (frames.reverse + [nil]).each_cons(2).each_with_index.
103
123
  map do |(frame, caller), i|
104
124
  "#{i == 0 ? 'on' : 'from'} line #{frame.line}" +
105
125
  " of #{frame.filename || 'an unknown file'}" +
@@ -16,7 +16,7 @@ module Sass::Tree
16
16
 
17
17
  # @see Node#invisible?
18
18
  def invisible?
19
- !Sass::Util.ruby1_8?
19
+ true
20
20
  end
21
21
  end
22
22
  end
@@ -59,7 +59,7 @@ module Sass::Tree
59
59
 
60
60
  # Returns the number of lines in the comment.
61
61
  #
62
- # @return [Integer]
62
+ # @return [Fixnum]
63
63
  def lines
64
64
  @value.inject(0) do |s, e|
65
65
  next s + e.count("\n") if e.is_a?(String)
@@ -69,7 +69,7 @@ module Sass
69
69
 
70
70
  # The line of the document on which this node appeared.
71
71
  #
72
- # @return [Integer]
72
+ # @return [Fixnum]
73
73
  attr_accessor :line
74
74
 
75
75
  # The source range in the document on which this node appeared.
@@ -83,7 +83,7 @@ module Sass
83
83
  attr_writer :filename
84
84
 
85
85
  # The options hash for the node.
86
- # See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
86
+ # See {file:SASS_REFERENCE.md#options the Sass options documentation}.
87
87
  #
88
88
  # @return [{Symbol => Object}]
89
89
  attr_reader :options
@@ -151,7 +151,7 @@ module Sass
151
151
  # @return [Boolean]
152
152
  def invisible?; false; end
153
153
 
154
- # The output style. See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
154
+ # The output style. See {file:SASS_REFERENCE.md#options the Sass options documentation}.
155
155
  #
156
156
  # @return [Symbol]
157
157
  def style
@@ -20,7 +20,11 @@ module Sass::Tree
20
20
 
21
21
  # The value of the property.
22
22
  #
23
- # @return [Sass::Script::Tree::Node]
23
+ # For most properties, this will just contain a single Node. However, for
24
+ # CSS variables, it will contain multiple strings and nodes representing
25
+ # interpolation. Any adjacent strings will be merged together.
26
+ #
27
+ # @return [Array<String, Sass::Script::Tree::Node>]
24
28
  attr_accessor :value
25
29
 
26
30
  # The value of the property
@@ -39,7 +43,7 @@ module Sass::Tree
39
43
  # * This is a child property of another property
40
44
  # * The parent property has a value, and thus will be rendered
41
45
  #
42
- # @return [Integer]
46
+ # @return [Fixnum]
43
47
  attr_accessor :tabs
44
48
 
45
49
  # The source range in which the property name appears.
@@ -52,14 +56,22 @@ module Sass::Tree
52
56
  # @return [Sass::Source::Range]
53
57
  attr_accessor :value_source_range
54
58
 
59
+ # Whether this represents a CSS custom property.
60
+ #
61
+ # @return [Boolean]
62
+ def custom_property?
63
+ name.first.is_a?(String) && name.first.start_with?("--")
64
+ end
65
+
55
66
  # @param name [Array<String, Sass::Script::Tree::Node>] See \{#name}
56
- # @param value [Sass::Script::Tree::Node] See \{#value}
67
+ # @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
57
68
  # @param prop_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
58
69
  # `:old` if it uses `:a b`-style syntax
59
70
  def initialize(name, value, prop_syntax)
60
71
  @name = Sass::Util.strip_string_array(
61
72
  Sass::Util.merge_adjacent_strings(name))
62
- @value = value
73
+ @value = Sass::Util.merge_adjacent_strings(value)
74
+ @value = Sass::Util.strip_string_array(@value) unless custom_property?
63
75
  @tabs = 0
64
76
  @prop_syntax = prop_syntax
65
77
  super()
@@ -81,9 +93,10 @@ module Sass::Tree
81
93
  # @return [String] The message
82
94
  def pseudo_class_selector_message
83
95
  if @prop_syntax == :new ||
84
- !value.is_a?(Sass::Script::Tree::Literal) ||
85
- !value.value.is_a?(Sass::Script::Value::String) ||
86
- !value.value.value.empty?
96
+ custom_property? ||
97
+ !value.first.is_a?(Sass::Script::Tree::Literal) ||
98
+ !value.first.value.is_a?(Sass::Script::Value::String) ||
99
+ !value.first.value.value.empty?
87
100
  return ""
88
101
  end
89
102
 
@@ -98,73 +111,52 @@ module Sass::Tree
98
111
  # @param fmt [Symbol] `:scss` or `:sass`.
99
112
  def declaration(opts = {:old => @prop_syntax == :old}, fmt = :sass)
100
113
  name = self.name.map {|n| n.is_a?(String) ? n : n.to_sass(opts)}.join
114
+ value = self.value.map {|n| n.is_a?(String) ? n : n.to_sass(opts)}.join
115
+ value = "(#{value})" if value_needs_parens?
116
+
101
117
  if name[0] == ?:
102
- raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\"" +
118
+ raise Sass::SyntaxError.new("The \"#{name}: #{value}\"" +
103
119
  " hack is not allowed in the Sass indented syntax")
104
120
  end
105
121
 
122
+ # The indented syntax doesn't support newlines in custom property values,
123
+ # but we can losslessly convert them to spaces instead.
124
+ value = value.tr("\n", " ") if fmt == :sass
125
+
106
126
  old = opts[:old] && fmt == :sass
107
- initial = old ? ':' : ''
108
- mid = old ? '' : ':'
109
- "#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
127
+ "#{old ? ':' : ''}#{name}#{old ? '' : ':'}#{custom_property? ? '' : ' '}#{value}".rstrip
110
128
  end
111
129
 
112
130
  # A property node is invisible if its value is empty.
113
131
  #
114
132
  # @return [Boolean]
115
133
  def invisible?
116
- resolved_value.empty?
134
+ !custom_property? && resolved_value.empty?
117
135
  end
118
136
 
119
137
  private
120
138
 
139
+ # Returns whether \{#value} neesd parentheses in order to be parsed
140
+ # properly as division.
141
+ def value_needs_parens?
142
+ return false if custom_property?
143
+
144
+ root = value.first
145
+ root.is_a?(Sass::Script::Tree::Operation) &&
146
+ root.operator == :div &&
147
+ root.operand1.is_a?(Sass::Script::Tree::Literal) &&
148
+ root.operand1.value.is_a?(Sass::Script::Value::Number) &&
149
+ root.operand1.value.original.nil? &&
150
+ root.operand2.is_a?(Sass::Script::Tree::Literal) &&
151
+ root.operand2.value.is_a?(Sass::Script::Value::Number) &&
152
+ root.operand2.value.original.nil?
153
+ end
154
+
121
155
  def check!
122
156
  return unless @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
123
157
  raise Sass::SyntaxError.new(
124
158
  "Illegal property syntax: can't use #{@prop_syntax} syntax when " +
125
159
  ":property_syntax => #{@options[:property_syntax].inspect} is set.")
126
160
  end
127
-
128
- class << self
129
- # @private
130
- def val_to_sass(value, opts)
131
- val_to_sass_comma(value, opts).to_sass(opts)
132
- end
133
-
134
- private
135
-
136
- def val_to_sass_comma(node, opts)
137
- return node unless node.is_a?(Sass::Script::Tree::Operation)
138
- return val_to_sass_concat(node, opts) unless node.operator == :comma
139
-
140
- Sass::Script::Tree::Operation.new(
141
- val_to_sass_concat(node.operand1, opts),
142
- val_to_sass_comma(node.operand2, opts),
143
- node.operator)
144
- end
145
-
146
- def val_to_sass_concat(node, opts)
147
- return node unless node.is_a?(Sass::Script::Tree::Operation)
148
- return val_to_sass_div(node, opts) unless node.operator == :space
149
-
150
- Sass::Script::Tree::Operation.new(
151
- val_to_sass_div(node.operand1, opts),
152
- val_to_sass_concat(node.operand2, opts),
153
- node.operator)
154
- end
155
-
156
- def val_to_sass_div(node, opts)
157
- unless node.is_a?(Sass::Script::Tree::Operation) && node.operator == :div &&
158
- node.operand1.is_a?(Sass::Script::Tree::Literal) &&
159
- node.operand1.value.is_a?(Sass::Script::Value::Number) &&
160
- node.operand2.is_a?(Sass::Script::Tree::Literal) &&
161
- node.operand2.value.is_a?(Sass::Script::Value::Number) &&
162
- (!node.operand1.value.original || !node.operand2.value.original)
163
- return node
164
- end
165
-
166
- Sass::Script::Value::String.new("(#{node.to_sass(opts)})")
167
- end
168
- end
169
161
  end
170
162
  end