aliddle-sass 1.0

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 (238) hide show
  1. data/.yardopts +11 -0
  2. data/CONTRIBUTING +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +201 -0
  5. data/Rakefile +347 -0
  6. data/VERSION +1 -0
  7. data/VERSION_NAME +1 -0
  8. data/bin/sass +9 -0
  9. data/bin/sass-convert +8 -0
  10. data/bin/scss +9 -0
  11. data/extra/update_watch.rb +13 -0
  12. data/init.rb +18 -0
  13. data/lib/sass.rb +95 -0
  14. data/lib/sass/cache_stores.rb +15 -0
  15. data/lib/sass/cache_stores/base.rb +88 -0
  16. data/lib/sass/cache_stores/chain.rb +33 -0
  17. data/lib/sass/cache_stores/filesystem.rb +60 -0
  18. data/lib/sass/cache_stores/memory.rb +47 -0
  19. data/lib/sass/cache_stores/null.rb +25 -0
  20. data/lib/sass/callbacks.rb +66 -0
  21. data/lib/sass/css.rb +409 -0
  22. data/lib/sass/engine.rb +928 -0
  23. data/lib/sass/environment.rb +101 -0
  24. data/lib/sass/error.rb +201 -0
  25. data/lib/sass/exec.rb +707 -0
  26. data/lib/sass/importers.rb +22 -0
  27. data/lib/sass/importers/base.rb +139 -0
  28. data/lib/sass/importers/filesystem.rb +190 -0
  29. data/lib/sass/logger.rb +15 -0
  30. data/lib/sass/logger/base.rb +32 -0
  31. data/lib/sass/logger/log_level.rb +49 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin.rb +132 -0
  34. data/lib/sass/plugin/compiler.rb +406 -0
  35. data/lib/sass/plugin/configuration.rb +123 -0
  36. data/lib/sass/plugin/generic.rb +15 -0
  37. data/lib/sass/plugin/merb.rb +48 -0
  38. data/lib/sass/plugin/rack.rb +60 -0
  39. data/lib/sass/plugin/rails.rb +47 -0
  40. data/lib/sass/plugin/staleness_checker.rb +183 -0
  41. data/lib/sass/railtie.rb +9 -0
  42. data/lib/sass/repl.rb +57 -0
  43. data/lib/sass/root.rb +7 -0
  44. data/lib/sass/script.rb +39 -0
  45. data/lib/sass/script/arg_list.rb +52 -0
  46. data/lib/sass/script/bool.rb +18 -0
  47. data/lib/sass/script/color.rb +606 -0
  48. data/lib/sass/script/css_lexer.rb +29 -0
  49. data/lib/sass/script/css_parser.rb +31 -0
  50. data/lib/sass/script/funcall.rb +237 -0
  51. data/lib/sass/script/functions.rb +1543 -0
  52. data/lib/sass/script/interpolation.rb +79 -0
  53. data/lib/sass/script/lexer.rb +348 -0
  54. data/lib/sass/script/list.rb +85 -0
  55. data/lib/sass/script/literal.rb +221 -0
  56. data/lib/sass/script/node.rb +99 -0
  57. data/lib/sass/script/null.rb +37 -0
  58. data/lib/sass/script/number.rb +453 -0
  59. data/lib/sass/script/operation.rb +110 -0
  60. data/lib/sass/script/parser.rb +495 -0
  61. data/lib/sass/script/string.rb +51 -0
  62. data/lib/sass/script/string_interpolation.rb +103 -0
  63. data/lib/sass/script/unary_operation.rb +69 -0
  64. data/lib/sass/script/variable.rb +58 -0
  65. data/lib/sass/scss.rb +16 -0
  66. data/lib/sass/scss/css_parser.rb +36 -0
  67. data/lib/sass/scss/parser.rb +1179 -0
  68. data/lib/sass/scss/rx.rb +133 -0
  69. data/lib/sass/scss/script_lexer.rb +15 -0
  70. data/lib/sass/scss/script_parser.rb +25 -0
  71. data/lib/sass/scss/static_parser.rb +54 -0
  72. data/lib/sass/selector.rb +452 -0
  73. data/lib/sass/selector/abstract_sequence.rb +94 -0
  74. data/lib/sass/selector/comma_sequence.rb +92 -0
  75. data/lib/sass/selector/sequence.rb +507 -0
  76. data/lib/sass/selector/simple.rb +119 -0
  77. data/lib/sass/selector/simple_sequence.rb +212 -0
  78. data/lib/sass/shared.rb +76 -0
  79. data/lib/sass/supports.rb +229 -0
  80. data/lib/sass/tree/charset_node.rb +22 -0
  81. data/lib/sass/tree/comment_node.rb +82 -0
  82. data/lib/sass/tree/content_node.rb +9 -0
  83. data/lib/sass/tree/css_import_node.rb +60 -0
  84. data/lib/sass/tree/debug_node.rb +18 -0
  85. data/lib/sass/tree/directive_node.rb +42 -0
  86. data/lib/sass/tree/each_node.rb +24 -0
  87. data/lib/sass/tree/extend_node.rb +36 -0
  88. data/lib/sass/tree/for_node.rb +36 -0
  89. data/lib/sass/tree/function_node.rb +34 -0
  90. data/lib/sass/tree/if_node.rb +52 -0
  91. data/lib/sass/tree/import_node.rb +75 -0
  92. data/lib/sass/tree/media_node.rb +58 -0
  93. data/lib/sass/tree/mixin_def_node.rb +38 -0
  94. data/lib/sass/tree/mixin_node.rb +39 -0
  95. data/lib/sass/tree/node.rb +196 -0
  96. data/lib/sass/tree/prop_node.rb +152 -0
  97. data/lib/sass/tree/return_node.rb +18 -0
  98. data/lib/sass/tree/root_node.rb +28 -0
  99. data/lib/sass/tree/rule_node.rb +132 -0
  100. data/lib/sass/tree/supports_node.rb +51 -0
  101. data/lib/sass/tree/trace_node.rb +32 -0
  102. data/lib/sass/tree/variable_node.rb +30 -0
  103. data/lib/sass/tree/visitors/base.rb +75 -0
  104. data/lib/sass/tree/visitors/check_nesting.rb +147 -0
  105. data/lib/sass/tree/visitors/convert.rb +316 -0
  106. data/lib/sass/tree/visitors/cssize.rb +229 -0
  107. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  108. data/lib/sass/tree/visitors/extend.rb +68 -0
  109. data/lib/sass/tree/visitors/perform.rb +446 -0
  110. data/lib/sass/tree/visitors/set_options.rb +125 -0
  111. data/lib/sass/tree/visitors/to_css.rb +230 -0
  112. data/lib/sass/tree/warn_node.rb +18 -0
  113. data/lib/sass/tree/while_node.rb +18 -0
  114. data/lib/sass/util.rb +906 -0
  115. data/lib/sass/util/multibyte_string_scanner.rb +155 -0
  116. data/lib/sass/util/subset_map.rb +109 -0
  117. data/lib/sass/util/test.rb +10 -0
  118. data/lib/sass/version.rb +126 -0
  119. data/rails/init.rb +1 -0
  120. data/test/Gemfile +3 -0
  121. data/test/Gemfile.lock +10 -0
  122. data/test/sass/cache_test.rb +89 -0
  123. data/test/sass/callbacks_test.rb +61 -0
  124. data/test/sass/conversion_test.rb +1760 -0
  125. data/test/sass/css2sass_test.rb +439 -0
  126. data/test/sass/data/hsl-rgb.txt +319 -0
  127. data/test/sass/engine_test.rb +3243 -0
  128. data/test/sass/exec_test.rb +86 -0
  129. data/test/sass/extend_test.rb +1461 -0
  130. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  131. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  132. data/test/sass/functions_test.rb +1139 -0
  133. data/test/sass/importer_test.rb +192 -0
  134. data/test/sass/logger_test.rb +58 -0
  135. data/test/sass/mock_importer.rb +49 -0
  136. data/test/sass/more_results/more1.css +9 -0
  137. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  138. data/test/sass/more_results/more_import.css +29 -0
  139. data/test/sass/more_templates/_more_partial.sass +2 -0
  140. data/test/sass/more_templates/more1.sass +23 -0
  141. data/test/sass/more_templates/more_import.sass +11 -0
  142. data/test/sass/plugin_test.rb +550 -0
  143. data/test/sass/results/alt.css +4 -0
  144. data/test/sass/results/basic.css +9 -0
  145. data/test/sass/results/cached_import_option.css +3 -0
  146. data/test/sass/results/compact.css +5 -0
  147. data/test/sass/results/complex.css +86 -0
  148. data/test/sass/results/compressed.css +1 -0
  149. data/test/sass/results/expanded.css +19 -0
  150. data/test/sass/results/filename_fn.css +3 -0
  151. data/test/sass/results/if.css +3 -0
  152. data/test/sass/results/import.css +31 -0
  153. data/test/sass/results/import_charset.css +5 -0
  154. data/test/sass/results/import_charset_1_8.css +5 -0
  155. data/test/sass/results/import_charset_ibm866.css +5 -0
  156. data/test/sass/results/import_content.css +1 -0
  157. data/test/sass/results/line_numbers.css +49 -0
  158. data/test/sass/results/mixins.css +95 -0
  159. data/test/sass/results/multiline.css +24 -0
  160. data/test/sass/results/nested.css +22 -0
  161. data/test/sass/results/options.css +1 -0
  162. data/test/sass/results/parent_ref.css +13 -0
  163. data/test/sass/results/script.css +16 -0
  164. data/test/sass/results/scss_import.css +31 -0
  165. data/test/sass/results/scss_importee.css +2 -0
  166. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  167. data/test/sass/results/subdir/subdir.css +3 -0
  168. data/test/sass/results/units.css +11 -0
  169. data/test/sass/results/warn.css +0 -0
  170. data/test/sass/results/warn_imported.css +0 -0
  171. data/test/sass/script_conversion_test.rb +299 -0
  172. data/test/sass/script_test.rb +591 -0
  173. data/test/sass/scss/css_test.rb +1093 -0
  174. data/test/sass/scss/rx_test.rb +156 -0
  175. data/test/sass/scss/scss_test.rb +2043 -0
  176. data/test/sass/scss/test_helper.rb +37 -0
  177. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  178. data/test/sass/templates/_double_import_loop2.sass +1 -0
  179. data/test/sass/templates/_filename_fn_import.scss +11 -0
  180. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  181. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  182. data/test/sass/templates/_imported_content.sass +3 -0
  183. data/test/sass/templates/_partial.sass +2 -0
  184. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  185. data/test/sass/templates/alt.sass +16 -0
  186. data/test/sass/templates/basic.sass +23 -0
  187. data/test/sass/templates/bork1.sass +2 -0
  188. data/test/sass/templates/bork2.sass +2 -0
  189. data/test/sass/templates/bork3.sass +2 -0
  190. data/test/sass/templates/bork4.sass +2 -0
  191. data/test/sass/templates/bork5.sass +3 -0
  192. data/test/sass/templates/cached_import_option.scss +3 -0
  193. data/test/sass/templates/compact.sass +17 -0
  194. data/test/sass/templates/complex.sass +305 -0
  195. data/test/sass/templates/compressed.sass +15 -0
  196. data/test/sass/templates/double_import_loop1.sass +1 -0
  197. data/test/sass/templates/expanded.sass +17 -0
  198. data/test/sass/templates/filename_fn.scss +18 -0
  199. data/test/sass/templates/if.sass +11 -0
  200. data/test/sass/templates/import.sass +12 -0
  201. data/test/sass/templates/import_charset.sass +9 -0
  202. data/test/sass/templates/import_charset_1_8.sass +6 -0
  203. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  204. data/test/sass/templates/import_content.sass +4 -0
  205. data/test/sass/templates/importee.less +2 -0
  206. data/test/sass/templates/importee.sass +19 -0
  207. data/test/sass/templates/line_numbers.sass +13 -0
  208. data/test/sass/templates/mixin_bork.sass +5 -0
  209. data/test/sass/templates/mixins.sass +76 -0
  210. data/test/sass/templates/multiline.sass +20 -0
  211. data/test/sass/templates/nested.sass +25 -0
  212. data/test/sass/templates/nested_bork1.sass +2 -0
  213. data/test/sass/templates/nested_bork2.sass +2 -0
  214. data/test/sass/templates/nested_bork3.sass +2 -0
  215. data/test/sass/templates/nested_bork4.sass +2 -0
  216. data/test/sass/templates/nested_import.sass +2 -0
  217. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  218. data/test/sass/templates/options.sass +2 -0
  219. data/test/sass/templates/parent_ref.sass +25 -0
  220. data/test/sass/templates/same_name_different_ext.sass +2 -0
  221. data/test/sass/templates/same_name_different_ext.scss +1 -0
  222. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  223. data/test/sass/templates/script.sass +101 -0
  224. data/test/sass/templates/scss_import.scss +11 -0
  225. data/test/sass/templates/scss_importee.scss +1 -0
  226. data/test/sass/templates/single_import_loop.sass +1 -0
  227. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  228. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  229. data/test/sass/templates/subdir/subdir.sass +6 -0
  230. data/test/sass/templates/units.sass +11 -0
  231. data/test/sass/templates/warn.sass +3 -0
  232. data/test/sass/templates/warn_imported.sass +4 -0
  233. data/test/sass/test_helper.rb +8 -0
  234. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  235. data/test/sass/util/subset_map_test.rb +91 -0
  236. data/test/sass/util_test.rb +313 -0
  237. data/test/test_helper.rb +80 -0
  238. metadata +348 -0
@@ -0,0 +1,119 @@
1
+ module Sass
2
+ module Selector
3
+ # The abstract superclass for simple selectors
4
+ # (that is, those that don't compose multiple selectors).
5
+ class Simple
6
+ # The line of the Sass template on which this selector was declared.
7
+ #
8
+ # @return [Fixnum]
9
+ attr_accessor :line
10
+
11
+ # The name of the file in which this selector was declared,
12
+ # or `nil` if it was not declared in a file (e.g. on stdin).
13
+ #
14
+ # @return [String, nil]
15
+ attr_accessor :filename
16
+
17
+ # Returns a representation of the node
18
+ # as an array of strings and potentially {Sass::Script::Node}s
19
+ # (if there's interpolation in the selector).
20
+ # When the interpolation is resolved and the strings are joined together,
21
+ # this will be the string representation of this node.
22
+ #
23
+ # @return [Array<String, Sass::Script::Node>]
24
+ def to_a
25
+ Sass::Util.abstract(self)
26
+ end
27
+
28
+ # Returns a string representation of the node.
29
+ # This is basically the selector string.
30
+ #
31
+ # @return [String]
32
+ def inspect
33
+ to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
34
+ end
35
+
36
+ # @see \{#inspect}
37
+ # @return [String]
38
+ def to_s
39
+ inspect
40
+ end
41
+
42
+ # Returns a hash code for this selector object.
43
+ #
44
+ # By default, this is based on the value of \{#to\_a},
45
+ # so if that contains information irrelevant to the identity of the selector,
46
+ # this should be overridden.
47
+ #
48
+ # @return [Fixnum]
49
+ def hash
50
+ @_hash ||= to_a.hash
51
+ end
52
+
53
+ # Checks equality between this and another object.
54
+ #
55
+ # By default, this is based on the value of \{#to\_a},
56
+ # so if that contains information irrelevant to the identity of the selector,
57
+ # this should be overridden.
58
+ #
59
+ # @param other [Object] The object to test equality against
60
+ # @return [Boolean] Whether or not this is equal to `other`
61
+ def eql?(other)
62
+ other.class == self.class && other.hash == self.hash && other.to_a.eql?(to_a)
63
+ end
64
+ alias_method :==, :eql?
65
+
66
+ # Unifies this selector with a {SimpleSequence}'s {SimpleSequence#members members array},
67
+ # returning another `SimpleSequence` members array
68
+ # that matches both this selector and the input selector.
69
+ #
70
+ # By default, this just appends this selector to the end of the array
71
+ # (or returns the original array if this selector already exists in it).
72
+ #
73
+ # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
74
+ # @return [Array<Simple>, nil] A {SimpleSequence} {SimpleSequence#members members array}
75
+ # matching both `sels` and this selector,
76
+ # or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
77
+ # @raise [Sass::SyntaxError] If this selector cannot be unified.
78
+ # This will only ever occur when a dynamic selector,
79
+ # such as {Parent} or {Interpolation}, is used in unification.
80
+ # Since these selectors should be resolved
81
+ # by the time extension and unification happen,
82
+ # this exception will only ever be raised as a result of programmer error
83
+ def unify(sels)
84
+ return sels if sels.any? {|sel2| eql?(sel2)}
85
+ sels_with_ix = Sass::Util.enum_with_index(sels)
86
+ _, i =
87
+ if self.is_a?(Pseudo) || self.is_a?(SelectorPseudoClass)
88
+ sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.type == :element)}
89
+ else
90
+ sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(SelectorPseudoClass)}
91
+ end
92
+ return sels + [self] unless i
93
+ return sels[0...i] + [self] + sels[i..-1]
94
+ end
95
+
96
+ protected
97
+
98
+ # Unifies two namespaces,
99
+ # returning a namespace that works for both of them if possible.
100
+ #
101
+ # @param ns1 [String, nil] The first namespace.
102
+ # `nil` means none specified, e.g. `foo`.
103
+ # The empty string means no namespace specified, e.g. `|foo`.
104
+ # `"*"` means any namespace is allowed, e.g. `*|foo`.
105
+ # @param ns2 [String, nil] The second namespace. See `ns1`.
106
+ # @return [Array(String or nil, Boolean)]
107
+ # The first value is the unified namespace, or `nil` for no namespace.
108
+ # The second value is whether or not a namespace that works for both inputs
109
+ # could be found at all.
110
+ # If the second value is `false`, the first should be ignored.
111
+ def unify_namespaces(ns1, ns2)
112
+ return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == ['*'] || ns2.nil? || ns2 == ['*']
113
+ return ns2, true if ns1 == ['*']
114
+ return ns1, true if ns2 == ['*']
115
+ return ns1 || ns2, true
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,212 @@
1
+ module Sass
2
+ module Selector
3
+ # A unseparated sequence of selectors
4
+ # that all apply to a single element.
5
+ # For example, `.foo#bar[attr=baz]` is a simple sequence
6
+ # of the selectors `.foo`, `#bar`, and `[attr=baz]`.
7
+ class SimpleSequence < AbstractSequence
8
+ # The array of individual selectors.
9
+ #
10
+ # @return [Array<Simple>]
11
+ attr_accessor :members
12
+
13
+ # The extending selectors that caused this selector sequence to be
14
+ # generated. For example:
15
+ #
16
+ # a.foo { ... }
17
+ # b.bar {@extend a}
18
+ # c.baz {@extend b}
19
+ #
20
+ # The generated selector `b.foo.bar` has `{b.bar}` as its `sources` set,
21
+ # and the generated selector `c.foo.bar.baz` has `{b.bar, c.baz}` as its
22
+ # `sources` set.
23
+ #
24
+ # This is populated during the {#do_extend} process.
25
+ #
26
+ # @return {Set<Sequence>}
27
+ attr_accessor :sources
28
+
29
+ # @see \{#subject?}
30
+ attr_writer :subject
31
+
32
+ # Returns the element or universal selector in this sequence,
33
+ # if it exists.
34
+ #
35
+ # @return [Element, Universal, nil]
36
+ def base
37
+ @base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
38
+ end
39
+
40
+ def pseudo_elements
41
+ @pseudo_elements ||= (members - [base]).
42
+ select {|sel| sel.is_a?(Pseudo) && sel.type == :element}
43
+ end
44
+
45
+ # Returns the non-base, non-pseudo-class selectors in this sequence.
46
+ #
47
+ # @return [Set<Simple>]
48
+ def rest
49
+ @rest ||= Set.new(members - [base] - pseudo_elements)
50
+ end
51
+
52
+ # Whether or not this compound selector is the subject of the parent
53
+ # selector; that is, whether it is prepended with `$` and represents the
54
+ # actual element that will be selected.
55
+ #
56
+ # @return [Boolean]
57
+ def subject?
58
+ @subject
59
+ end
60
+
61
+ # @param selectors [Array<Simple>] See \{#members}
62
+ # @param subject [Boolean] See \{#subject?}
63
+ # @param sources [Set<Sequence>]
64
+ def initialize(selectors, subject, sources = Set.new)
65
+ @members = selectors
66
+ @subject = subject
67
+ @sources = sources
68
+ end
69
+
70
+ # Resolves the {Parent} selectors within this selector
71
+ # by replacing them with the given parent selector,
72
+ # handling commas appropriately.
73
+ #
74
+ # @param super_seq [Sequence] The parent selector sequence
75
+ # @return [Array<SimpleSequence>] This selector, with parent references resolved.
76
+ # This is an array because the parent selector is itself a {Sequence}
77
+ # @raise [Sass::SyntaxError] If a parent selector is invalid
78
+ def resolve_parent_refs(super_seq)
79
+ # Parent selector only appears as the first selector in the sequence
80
+ return [self] unless @members.first.is_a?(Parent)
81
+
82
+ return super_seq.members if @members.size == 1
83
+ unless super_seq.members.last.is_a?(SimpleSequence)
84
+ raise Sass::SyntaxError.new("Invalid parent selector: " + super_seq.to_a.join)
85
+ end
86
+
87
+ super_seq.members[0...-1] +
88
+ [SimpleSequence.new(super_seq.members.last.members + @members[1..-1], subject?)]
89
+ end
90
+
91
+ # Non-destrucively extends this selector with the extensions specified in a hash
92
+ # (which should come from {Sass::Tree::Visitors::Cssize}).
93
+ #
94
+ # @overload def do_extend(extends, parent_directives)
95
+ # @param extends [{Selector::Simple =>
96
+ # Sass::Tree::Visitors::Cssize::Extend}]
97
+ # The extensions to perform on this selector
98
+ # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
99
+ # The directives containing this selector.
100
+ # @return [Array<Sequence>] A list of selectors generated
101
+ # by extending this selector with `extends`.
102
+ # @see CommaSequence#do_extend
103
+ def do_extend(extends, parent_directives, seen = Set.new)
104
+ Sass::Util.group_by_to_a(extends.get(members.to_set)) {|ex, _| ex.extender}.map do |seq, group|
105
+ sels = group.map {|_, s| s}.flatten
106
+ # If A {@extend B} and C {...},
107
+ # seq is A, sels is B, and self is C
108
+
109
+ self_without_sel = Sass::Util.array_minus(self.members, sels)
110
+ group.each {|e, _| e.result = :failed_to_unify unless e.result == :succeeded}
111
+ next unless unified = seq.members.last.unify(self_without_sel, subject?)
112
+ group.each {|e, _| e.result = :succeeded}
113
+ next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
114
+ new_seq = Sequence.new(seq.members[0...-1] + [unified])
115
+ new_seq.add_sources!(sources + [seq])
116
+ [sels, new_seq]
117
+ end.compact.map do |sels, seq|
118
+ seen.include?(sels) ? [] : seq.do_extend(extends, parent_directives, seen + [sels])
119
+ end.flatten.uniq
120
+ end
121
+
122
+ # Unifies this selector with another {SimpleSequence}'s {SimpleSequence#members members array},
123
+ # returning another `SimpleSequence`
124
+ # that matches both this selector and the input selector.
125
+ #
126
+ # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
127
+ # @param subject [Boolean] Whether the {SimpleSequence} being merged is a subject.
128
+ # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
129
+ # or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
130
+ # @raise [Sass::SyntaxError] If this selector cannot be unified.
131
+ # This will only ever occur when a dynamic selector,
132
+ # such as {Parent} or {Interpolation}, is used in unification.
133
+ # Since these selectors should be resolved
134
+ # by the time extension and unification happen,
135
+ # this exception will only ever be raised as a result of programmer error
136
+ def unify(sels, other_subject)
137
+ return unless sseq = members.inject(sels) do |member, sel|
138
+ return unless member
139
+ sel.unify(member)
140
+ end
141
+ SimpleSequence.new(sseq, other_subject || subject?)
142
+ end
143
+
144
+ # Returns whether or not this selector matches all elements
145
+ # that the given selector matches (as well as possibly more).
146
+ #
147
+ # @example
148
+ # (.foo).superselector?(.foo.bar) #=> true
149
+ # (.foo).superselector?(.bar) #=> false
150
+ # @param sseq [SimpleSequence]
151
+ # @return [Boolean]
152
+ def superselector?(sseq)
153
+ (base.nil? || base.eql?(sseq.base)) &&
154
+ pseudo_elements.eql?(sseq.pseudo_elements) &&
155
+ rest.subset?(sseq.rest)
156
+ end
157
+
158
+ # @see Simple#to_a
159
+ def to_a
160
+ res = @members.map {|sel| sel.to_a}.flatten
161
+ res << '!' if subject?
162
+ res
163
+ end
164
+
165
+ # Returns a string representation of the sequence.
166
+ # This is basically the selector string.
167
+ #
168
+ # @return [String]
169
+ def inspect
170
+ members.map {|m| m.inspect}.join
171
+ end
172
+
173
+ # Return a copy of this simple sequence with `sources` merged into the
174
+ # {#sources} set.
175
+ #
176
+ # @param sources [Set<Sequence>]
177
+ # @return [SimpleSequence]
178
+ def with_more_sources(sources)
179
+ sseq = dup
180
+ sseq.members = members.dup
181
+ sseq.sources = self.sources | sources
182
+ sseq
183
+ end
184
+
185
+ private
186
+
187
+ def check_directives_match!(extend, parent_directives)
188
+ dirs1 = extend.directives.map {|d| d.resolved_value}
189
+ dirs2 = parent_directives.map {|d| d.resolved_value}
190
+ return true if Sass::Util.subsequence?(dirs1, dirs2)
191
+
192
+ Sass::Util.sass_warn <<WARNING
193
+ DEPRECATION WARNING on line #{extend.node.line}#{" of #{extend.node.filename}" if extend.node.filename}:
194
+ @extending an outer selector from within #{extend.directives.last.name} is deprecated.
195
+ You may only @extend selectors within the same directive.
196
+ This will be an error in Sass 3.3.
197
+ It can only work once @extend is supported natively in the browser.
198
+ WARNING
199
+ return false
200
+ end
201
+
202
+ def _hash
203
+ [base, Sass::Util.set_hash(rest)].hash
204
+ end
205
+
206
+ def _eql?(other)
207
+ other.base.eql?(self.base) && other.pseudo_elements == pseudo_elements &&
208
+ Sass::Util.set_eql?(other.rest, self.rest) && other.subject? == self.subject?
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,76 @@
1
+ module Sass
2
+ # This module contains functionality that's shared between Haml and Sass.
3
+ module Shared
4
+ extend self
5
+
6
+ # Scans through a string looking for the interoplation-opening `#{`
7
+ # and, when it's found, yields the scanner to the calling code
8
+ # so it can handle it properly.
9
+ #
10
+ # The scanner will have any backslashes immediately in front of the `#{`
11
+ # as the second capture group (`scan[2]`),
12
+ # and the text prior to that as the first (`scan[1]`).
13
+ #
14
+ # @yieldparam scan [StringScanner] The scanner scanning through the string
15
+ # @return [String] The text remaining in the scanner after all `#{`s have been processed
16
+ def handle_interpolation(str)
17
+ scan = Sass::Util::MultibyteStringScanner.new(str)
18
+ yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
19
+ scan.rest
20
+ end
21
+
22
+ # Moves a scanner through a balanced pair of characters.
23
+ # For example:
24
+ #
25
+ # Foo (Bar (Baz bang) bop) (Bang (bop bip))
26
+ # ^ ^
27
+ # from to
28
+ #
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 [Fixnum] The number of opening characters matched
35
+ # before calling this method
36
+ # @return [(String, String)] The string matched within the balanced pair
37
+ # and the rest of the string.
38
+ # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
39
+ def balance(scanner, start, finish, count = 0)
40
+ str = ''
41
+ scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
42
+ regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
43
+ while scanner.scan(regexp)
44
+ str << scanner.matched
45
+ count += 1 if scanner.matched[-1] == start
46
+ count -= 1 if scanner.matched[-1] == finish
47
+ return [str.strip, scanner.rest] if count == 0
48
+ end
49
+ end
50
+
51
+ # Formats a string for use in error messages about indentation.
52
+ #
53
+ # @param indentation [String] The string used for indentation
54
+ # @param was [Boolean] Whether or not to add `"was"` or `"were"`
55
+ # (depending on how many characters were in `indentation`)
56
+ # @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)
57
+ def human_indentation(indentation, was = false)
58
+ if !indentation.include?(?\t)
59
+ noun = 'space'
60
+ elsif !indentation.include?(?\s)
61
+ noun = 'tab'
62
+ else
63
+ return indentation.inspect + (was ? ' was' : '')
64
+ end
65
+
66
+ singular = indentation.length == 1
67
+ if was
68
+ was = singular ? ' was' : ' were'
69
+ else
70
+ was = ''
71
+ end
72
+
73
+ "#{indentation.length} #{noun}#{'s' unless singular}#{was}"
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,229 @@
1
+ # A namespace for the `@supports` condition parse tree.
2
+ module Sass::Supports
3
+ # The abstract superclass of all Supports conditions.
4
+ class Condition
5
+ # Runs the SassScript in the supports condition.
6
+ #
7
+ # @param env [Sass::Environment] The environment in which to run the script.
8
+ def perform(environment); Sass::Util.abstract(self); end
9
+
10
+ # Returns the CSS for this condition.
11
+ #
12
+ # @return [String]
13
+ def to_css; Sass::Util.abstract(self); end
14
+
15
+ # Returns the Sass/CSS code for this condition.
16
+ #
17
+ # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
18
+ # @return [String]
19
+ def to_src(options); Sass::Util.abstract(self); end
20
+
21
+ # Returns a deep copy of this condition and all its children.
22
+ #
23
+ # @return [Condition]
24
+ def deep_copy; Sass::Util.abstract(self); end
25
+
26
+ # Sets the options hash for the script nodes in the supports condition.
27
+ #
28
+ # @param options [{Symbol => Object}] The options has to set.
29
+ def options=(options); Sass::Util.abstract(self); end
30
+ end
31
+
32
+ # An operator condition (e.g. `CONDITION1 and CONDITION2`).
33
+ class Operator < Condition
34
+ # The left-hand condition.
35
+ #
36
+ # @return [Sass::Supports::Condition]
37
+ attr_accessor :left
38
+
39
+ # The right-hand condition.
40
+ #
41
+ # @return [Sass::Supports::Condition]
42
+ attr_accessor :right
43
+
44
+ # The operator ("and" or "or").
45
+ #
46
+ # @return [String]
47
+ attr_accessor :op
48
+
49
+ def initialize(left, right, op)
50
+ @left = left
51
+ @right = right
52
+ @op = op
53
+ end
54
+
55
+ def perform(env)
56
+ @left.perform(env)
57
+ @right.perform(env)
58
+ end
59
+
60
+ def to_css
61
+ "#{left_parens @left.to_css} #{op} #{right_parens @right.to_css}"
62
+ end
63
+
64
+ def to_src(options)
65
+ "#{left_parens @left.to_src(options)} #{op} #{right_parens @right.to_src(options)}"
66
+ end
67
+
68
+ def deep_copy
69
+ copy = dup
70
+ copy.left = @left.deep_copy
71
+ copy.right = @right.deep_copy
72
+ copy
73
+ end
74
+
75
+ def options=(options)
76
+ @left.options = options
77
+ @right.options = options
78
+ end
79
+
80
+ private
81
+
82
+ def left_parens(str)
83
+ return "(#{str})" if @left.is_a?(Negation)
84
+ return str
85
+ end
86
+
87
+ def right_parens(str)
88
+ return "(#{str})" if @right.is_a?(Negation) || @right.is_a?(Operator)
89
+ return str
90
+ end
91
+ end
92
+
93
+ # A negation condition (`not CONDITION`).
94
+ class Negation < Condition
95
+ # The condition being negated.
96
+ #
97
+ # @return [Sass::Supports::Condition]
98
+ attr_accessor :condition
99
+
100
+ def initialize(condition)
101
+ @condition = condition
102
+ end
103
+
104
+ def perform(env)
105
+ @condition.perform(env)
106
+ end
107
+
108
+ def to_css
109
+ "not #{parens @condition.to_css}"
110
+ end
111
+
112
+ def to_src(options)
113
+ "not #{parens @condition.to_src(options)}"
114
+ end
115
+
116
+ def deep_copy
117
+ copy = dup
118
+ copy.condition = condition.deep_copy
119
+ copy
120
+ end
121
+
122
+ def options=(options)
123
+ condition.options = options
124
+ end
125
+
126
+ private
127
+
128
+ def parens(str)
129
+ return "(#{str})" if @condition.is_a?(Negation) || @condition.is_a?(Operator)
130
+ return str
131
+ end
132
+ end
133
+
134
+ # A declaration condition (e.g. `(feature: value)`).
135
+ class Declaration < Condition
136
+ # The feature name.
137
+ #
138
+ # @param [Sass::Script::Node]
139
+ attr_accessor :name
140
+
141
+ # The name of the feature after any SassScript has been resolved.
142
+ # Only set once \{Tree::Visitors::Perform} has been run.
143
+ #
144
+ # @return [String]
145
+ attr_accessor :resolved_name
146
+
147
+ # The feature value.
148
+ #
149
+ # @param [Sass::Script::Node]
150
+ attr_accessor :value
151
+
152
+ # The value of the feature after any SassScript has been resolved.
153
+ # Only set once \{Tree::Visitors::Perform} has been run.
154
+ #
155
+ # @return [String]
156
+ attr_accessor :resolved_value
157
+
158
+ def initialize(name, value)
159
+ @name = name
160
+ @value = value
161
+ end
162
+
163
+ def perform(env)
164
+ @resolved_name = name.perform(env)
165
+ @resolved_value = value.perform(env)
166
+ end
167
+
168
+ def to_css
169
+ "(#{@resolved_name}: #{@resolved_value})"
170
+ end
171
+
172
+ def to_src(options)
173
+ "(#{@name.to_sass(options)}: #{@value.to_sass(options)})"
174
+ end
175
+
176
+ def deep_copy
177
+ copy = dup
178
+ copy.name = @name.deep_copy
179
+ copy.value = @value.deep_copy
180
+ copy
181
+ end
182
+
183
+ def options=(options)
184
+ @name.options = options
185
+ @value.options = options
186
+ end
187
+ end
188
+
189
+ # An interpolation condition (e.g. `#{$var}`).
190
+ class Interpolation < Condition
191
+ # The SassScript expression in the interpolation.
192
+ #
193
+ # @param [Sass::Script::Node]
194
+ attr_accessor :value
195
+
196
+ # The value of the expression after it's been resolved.
197
+ # Only set once \{Tree::Visitors::Perform} has been run.
198
+ #
199
+ # @return [String]
200
+ attr_accessor :resolved_value
201
+
202
+ def initialize(value)
203
+ @value = value
204
+ end
205
+
206
+ def perform(env)
207
+ val = value.perform(env)
208
+ @resolved_value = val.is_a?(Sass::Script::String) ? val.value : val.to_s
209
+ end
210
+
211
+ def to_css
212
+ @resolved_value
213
+ end
214
+
215
+ def to_src(options)
216
+ "\#{#{@value.to_sass(options)}}"
217
+ end
218
+
219
+ def deep_copy
220
+ copy = dup
221
+ copy.value = @value.deep_copy
222
+ copy
223
+ end
224
+
225
+ def options=(options)
226
+ @value.options = options
227
+ end
228
+ end
229
+ end