sass 3.4.25 → 3.5.0.pre.rc.1

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.
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