sass 3.4.25 → 3.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +1 -1
  3. data/CONTRIBUTING.md +3 -3
  4. data/README.md +17 -9
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/extra/sass-spec-ref.sh +9 -1
  9. data/lib/sass.rb +0 -7
  10. data/lib/sass/cache_stores/filesystem.rb +1 -1
  11. data/lib/sass/css.rb +1 -2
  12. data/lib/sass/engine.rb +39 -29
  13. data/lib/sass/environment.rb +26 -5
  14. data/lib/sass/error.rb +2 -2
  15. data/lib/sass/exec/base.rb +2 -13
  16. data/lib/sass/exec/sass_scss.rb +1 -5
  17. data/lib/sass/features.rb +1 -0
  18. data/lib/sass/importers/filesystem.rb +6 -4
  19. data/lib/sass/logger/base.rb +11 -0
  20. data/lib/sass/plugin/compiler.rb +20 -50
  21. data/lib/sass/plugin/configuration.rb +2 -2
  22. data/lib/sass/railtie.rb +1 -1
  23. data/lib/sass/script/css_parser.rb +4 -1
  24. data/lib/sass/script/functions.rb +308 -81
  25. data/lib/sass/script/lexer.rb +63 -9
  26. data/lib/sass/script/parser.rb +287 -118
  27. data/lib/sass/script/tree/funcall.rb +35 -34
  28. data/lib/sass/script/tree/interpolation.rb +0 -3
  29. data/lib/sass/script/tree/list_literal.rb +23 -8
  30. data/lib/sass/script/tree/map_literal.rb +2 -2
  31. data/lib/sass/script/tree/node.rb +0 -8
  32. data/lib/sass/script/tree/operation.rb +1 -8
  33. data/lib/sass/script/value.rb +2 -0
  34. data/lib/sass/script/value/arg_list.rb +1 -1
  35. data/lib/sass/script/value/base.rb +17 -0
  36. data/lib/sass/script/value/callable.rb +25 -0
  37. data/lib/sass/script/value/color.rb +8 -2
  38. data/lib/sass/script/value/function.rb +19 -0
  39. data/lib/sass/script/value/helpers.rb +37 -11
  40. data/lib/sass/script/value/list.rb +35 -14
  41. data/lib/sass/script/value/map.rb +2 -2
  42. data/lib/sass/script/value/number.rb +3 -2
  43. data/lib/sass/scss/css_parser.rb +6 -1
  44. data/lib/sass/scss/parser.rb +145 -56
  45. data/lib/sass/scss/rx.rb +5 -11
  46. data/lib/sass/scss/static_parser.rb +20 -42
  47. data/lib/sass/selector.rb +4 -0
  48. data/lib/sass/selector/abstract_sequence.rb +7 -6
  49. data/lib/sass/selector/comma_sequence.rb +9 -5
  50. data/lib/sass/selector/pseudo.rb +20 -3
  51. data/lib/sass/selector/sequence.rb +35 -10
  52. data/lib/sass/selector/simple.rb +9 -2
  53. data/lib/sass/selector/simple_sequence.rb +8 -4
  54. data/lib/sass/source/map.rb +2 -6
  55. data/lib/sass/stack.rb +21 -1
  56. data/lib/sass/tree/charset_node.rb +1 -1
  57. data/lib/sass/tree/prop_node.rb +45 -53
  58. data/lib/sass/tree/rule_node.rb +6 -8
  59. data/lib/sass/tree/visitors/check_nesting.rb +1 -1
  60. data/lib/sass/tree/visitors/convert.rb +2 -3
  61. data/lib/sass/tree/visitors/cssize.rb +4 -15
  62. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  63. data/lib/sass/tree/visitors/extend.rb +2 -8
  64. data/lib/sass/tree/visitors/perform.rb +23 -15
  65. data/lib/sass/tree/visitors/set_options.rb +1 -1
  66. data/lib/sass/tree/visitors/to_css.rb +49 -22
  67. data/lib/sass/util.rb +72 -310
  68. data/lib/sass/util/multibyte_string_scanner.rb +127 -131
  69. data/lib/sass/util/normalized_map.rb +1 -8
  70. data/lib/sass/version.rb +0 -4
  71. metadata +55 -202
  72. data/Rakefile +0 -453
  73. data/lib/sass/script/css_variable_warning.rb +0 -52
  74. data/lib/sass/util/cross_platform_random.rb +0 -19
  75. data/lib/sass/util/ordered_hash.rb +0 -192
  76. data/test/sass-spec.yml +0 -3
  77. data/test/sass/cache_test.rb +0 -131
  78. data/test/sass/callbacks_test.rb +0 -61
  79. data/test/sass/compiler_test.rb +0 -236
  80. data/test/sass/conversion_test.rb +0 -2188
  81. data/test/sass/css2sass_test.rb +0 -526
  82. data/test/sass/css_variable_test.rb +0 -132
  83. data/test/sass/data/hsl-rgb.txt +0 -319
  84. data/test/sass/encoding_test.rb +0 -219
  85. data/test/sass/engine_test.rb +0 -3447
  86. data/test/sass/exec_test.rb +0 -96
  87. data/test/sass/extend_test.rb +0 -1733
  88. data/test/sass/fixtures/test_staleness_check_across_importers.css +0 -1
  89. data/test/sass/fixtures/test_staleness_check_across_importers.scss +0 -1
  90. data/test/sass/functions_test.rb +0 -1977
  91. data/test/sass/importer_test.rb +0 -421
  92. data/test/sass/logger_test.rb +0 -58
  93. data/test/sass/mock_importer.rb +0 -49
  94. data/test/sass/more_results/more1.css +0 -9
  95. data/test/sass/more_results/more1_with_line_comments.css +0 -26
  96. data/test/sass/more_results/more_import.css +0 -29
  97. data/test/sass/more_templates/_more_partial.sass +0 -2
  98. data/test/sass/more_templates/more1.sass +0 -23
  99. data/test/sass/more_templates/more_import.sass +0 -11
  100. data/test/sass/plugin_test.rb +0 -556
  101. data/test/sass/results/alt.css +0 -4
  102. data/test/sass/results/basic.css +0 -9
  103. data/test/sass/results/cached_import_option.css +0 -3
  104. data/test/sass/results/compact.css +0 -5
  105. data/test/sass/results/complex.css +0 -86
  106. data/test/sass/results/compressed.css +0 -1
  107. data/test/sass/results/expanded.css +0 -19
  108. data/test/sass/results/filename_fn.css +0 -3
  109. data/test/sass/results/if.css +0 -3
  110. data/test/sass/results/import.css +0 -31
  111. data/test/sass/results/import_charset.css +0 -5
  112. data/test/sass/results/import_charset_1_8.css +0 -5
  113. data/test/sass/results/import_charset_ibm866.css +0 -5
  114. data/test/sass/results/import_content.css +0 -1
  115. data/test/sass/results/line_numbers.css +0 -49
  116. data/test/sass/results/mixins.css +0 -95
  117. data/test/sass/results/multiline.css +0 -24
  118. data/test/sass/results/nested.css +0 -22
  119. data/test/sass/results/options.css +0 -1
  120. data/test/sass/results/parent_ref.css +0 -13
  121. data/test/sass/results/script.css +0 -16
  122. data/test/sass/results/scss_import.css +0 -31
  123. data/test/sass/results/scss_importee.css +0 -2
  124. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
  125. data/test/sass/results/subdir/subdir.css +0 -3
  126. data/test/sass/results/units.css +0 -11
  127. data/test/sass/results/warn.css +0 -0
  128. data/test/sass/results/warn_imported.css +0 -0
  129. data/test/sass/script_conversion_test.rb +0 -357
  130. data/test/sass/script_test.rb +0 -1431
  131. data/test/sass/scss/css_test.rb +0 -1281
  132. data/test/sass/scss/rx_test.rb +0 -160
  133. data/test/sass/scss/scss_test.rb +0 -4205
  134. data/test/sass/scss/test_helper.rb +0 -37
  135. data/test/sass/source_map_test.rb +0 -1055
  136. data/test/sass/superselector_test.rb +0 -210
  137. data/test/sass/templates/_cached_import_option_partial.scss +0 -1
  138. data/test/sass/templates/_double_import_loop2.sass +0 -1
  139. data/test/sass/templates/_filename_fn_import.scss +0 -11
  140. data/test/sass/templates/_imported_charset_ibm866.sass +0 -4
  141. data/test/sass/templates/_imported_charset_utf8.sass +0 -4
  142. data/test/sass/templates/_imported_content.sass +0 -3
  143. data/test/sass/templates/_partial.sass +0 -2
  144. data/test/sass/templates/_same_name_different_partiality.scss +0 -1
  145. data/test/sass/templates/alt.sass +0 -16
  146. data/test/sass/templates/basic.sass +0 -23
  147. data/test/sass/templates/bork1.sass +0 -2
  148. data/test/sass/templates/bork2.sass +0 -2
  149. data/test/sass/templates/bork3.sass +0 -2
  150. data/test/sass/templates/bork4.sass +0 -2
  151. data/test/sass/templates/bork5.sass +0 -3
  152. data/test/sass/templates/cached_import_option.scss +0 -3
  153. data/test/sass/templates/compact.sass +0 -17
  154. data/test/sass/templates/complex.sass +0 -305
  155. data/test/sass/templates/compressed.sass +0 -15
  156. data/test/sass/templates/double_import_loop1.sass +0 -1
  157. data/test/sass/templates/expanded.sass +0 -17
  158. data/test/sass/templates/filename_fn.scss +0 -18
  159. data/test/sass/templates/if.sass +0 -11
  160. data/test/sass/templates/import.sass +0 -12
  161. data/test/sass/templates/import_charset.sass +0 -9
  162. data/test/sass/templates/import_charset_1_8.sass +0 -6
  163. data/test/sass/templates/import_charset_ibm866.sass +0 -11
  164. data/test/sass/templates/import_content.sass +0 -4
  165. data/test/sass/templates/importee.less +0 -2
  166. data/test/sass/templates/importee.sass +0 -19
  167. data/test/sass/templates/line_numbers.sass +0 -13
  168. data/test/sass/templates/mixin_bork.sass +0 -5
  169. data/test/sass/templates/mixins.sass +0 -76
  170. data/test/sass/templates/multiline.sass +0 -20
  171. data/test/sass/templates/nested.sass +0 -25
  172. data/test/sass/templates/nested_bork1.sass +0 -2
  173. data/test/sass/templates/nested_bork2.sass +0 -2
  174. data/test/sass/templates/nested_bork3.sass +0 -2
  175. data/test/sass/templates/nested_bork4.sass +0 -2
  176. data/test/sass/templates/nested_import.sass +0 -2
  177. data/test/sass/templates/nested_mixin_bork.sass +0 -6
  178. data/test/sass/templates/options.sass +0 -2
  179. data/test/sass/templates/parent_ref.sass +0 -25
  180. data/test/sass/templates/same_name_different_ext.sass +0 -2
  181. data/test/sass/templates/same_name_different_ext.scss +0 -1
  182. data/test/sass/templates/same_name_different_partiality.scss +0 -1
  183. data/test/sass/templates/script.sass +0 -101
  184. data/test/sass/templates/scss_import.scss +0 -12
  185. data/test/sass/templates/scss_importee.scss +0 -1
  186. data/test/sass/templates/single_import_loop.sass +0 -1
  187. data/test/sass/templates/subdir/import_up1.scss +0 -1
  188. data/test/sass/templates/subdir/import_up2.scss +0 -1
  189. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
  190. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
  191. data/test/sass/templates/subdir/subdir.sass +0 -6
  192. data/test/sass/templates/units.sass +0 -11
  193. data/test/sass/templates/warn.sass +0 -3
  194. data/test/sass/templates/warn_imported.sass +0 -4
  195. data/test/sass/test_helper.rb +0 -8
  196. data/test/sass/util/multibyte_string_scanner_test.rb +0 -155
  197. data/test/sass/util/normalized_map_test.rb +0 -51
  198. data/test/sass/util/subset_map_test.rb +0 -91
  199. data/test/sass/util_test.rb +0 -438
  200. data/test/sass/value_helpers_test.rb +0 -179
  201. data/test/test_helper.rb +0 -110
  202. data/vendor/listen/CHANGELOG.md +0 -1
  203. data/vendor/listen/CONTRIBUTING.md +0 -38
  204. data/vendor/listen/Gemfile +0 -20
  205. data/vendor/listen/Guardfile +0 -8
  206. data/vendor/listen/LICENSE +0 -20
  207. data/vendor/listen/README.md +0 -349
  208. data/vendor/listen/Rakefile +0 -5
  209. data/vendor/listen/Vagrantfile +0 -96
  210. data/vendor/listen/lib/listen.rb +0 -54
  211. data/vendor/listen/lib/listen/adapter.rb +0 -327
  212. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
  213. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
  214. data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
  215. data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
  216. data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
  217. data/vendor/listen/lib/listen/directory_record.rb +0 -406
  218. data/vendor/listen/lib/listen/listener.rb +0 -323
  219. data/vendor/listen/lib/listen/turnstile.rb +0 -32
  220. data/vendor/listen/lib/listen/version.rb +0 -3
  221. data/vendor/listen/listen.gemspec +0 -28
  222. data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
  223. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  224. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  225. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  226. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  227. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  228. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
  229. data/vendor/listen/spec/listen/listener_spec.rb +0 -258
  230. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  231. data/vendor/listen/spec/listen_spec.rb +0 -67
  232. data/vendor/listen/spec/spec_helper.rb +0 -25
  233. data/vendor/listen/spec/support/adapter_helper.rb +0 -666
  234. data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
  235. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  236. data/vendor/listen/spec/support/listeners_helper.rb +0 -179
  237. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -1,96 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require File.dirname(__FILE__) + '/../test_helper'
3
- require 'fileutils'
4
- require 'sass/util/test'
5
- require 'tmpdir'
6
-
7
- class ExecTest < MiniTest::Test
8
- include Sass::Util::Test
9
-
10
- def setup
11
- @dir = Dir.mktmpdir
12
- end
13
-
14
- def teardown
15
- FileUtils.rm_rf(@dir)
16
- clean_up_sassc
17
- end
18
-
19
- def test_scss_t_expanded
20
- src = get_path("src.scss")
21
- dest = get_path("dest.css")
22
- write(src, ".ruleset { margin: 0 }")
23
- assert(exec(*%w[scss --sourcemap=none -t expanded --unix-newlines].push(src, dest)))
24
- assert_equal(".ruleset {\n margin: 0;\n}\n", read(dest))
25
- end
26
-
27
- def test_sass_convert_T_sass
28
- src = get_path("src.scss")
29
- dest = get_path("dest.css")
30
- write(src, ".ruleset { margin: 0 }")
31
- assert(exec(*%w[sass-convert -T sass --unix-newlines].push(src, dest)))
32
- assert_equal(".ruleset\n margin: 0\n", read(dest))
33
- end
34
-
35
- def test_sass_convert_T_sass_in_place
36
- src = get_path("src.scss")
37
- write(src, ".ruleset { margin: 0 }")
38
- assert(exec(*%w[sass-convert -T sass --in-place --unix-newlines].push(src)))
39
- assert_equal(".ruleset\n margin: 0\n", read(src))
40
- end
41
-
42
- def test_scss_t_expanded_no_unix_newlines
43
- return skip "Can be run on Windows only" unless Sass::Util.windows?
44
- src = get_path("src.scss")
45
- dest = get_path("dest.css")
46
- write(src, ".ruleset { margin: 0 }")
47
- assert(exec(*%w[scss -t expanded].push(src, dest)))
48
- assert_equal(".ruleset {\r\n margin: 0;\r\n}\r\n", read(dest))
49
- end
50
-
51
- def test_sass_convert_T_sass_no_unix_newlines
52
- return skip "Can be run on Windows only" unless Sass::Util.windows?
53
- src = get_path("src.scss")
54
- dest = get_path("dest.sass")
55
- write(src, ".ruleset { margin: 0 }")
56
- assert(exec(*%w[sass-convert -T sass].push(src, dest)))
57
- assert_equal(".ruleset\r\n margin: 0\r\n", read(dest))
58
- end
59
-
60
- def test_sass_convert_T_sass_in_place_no_unix_newlines
61
- return skip "Can be run on Windows only" unless Sass::Util.windows?
62
- src = get_path("src.scss")
63
- write(src, ".ruleset { margin: 0 }")
64
- assert(exec(*%w[sass-convert -T sass --in-place].push(src)))
65
- assert_equal(".ruleset\r\n margin: 0\r\n", read(src))
66
- end
67
-
68
- def test_sass_convert_R
69
- Dir.chdir(@dir) do
70
- src = get_path("styles/src.css")
71
- write(src, ".ruleset { margin: 0 }")
72
- assert(exec(*%w[sass-convert -Rq --from css --to scss --trace styles]))
73
- end
74
- end
75
-
76
- private
77
-
78
- def get_path(name)
79
- File.join(@dir, name)
80
- end
81
-
82
- def read(file)
83
- open(file, 'rb') {|f| f.read}
84
- end
85
-
86
- def write(file, content)
87
- FileUtils.mkdir_p(File.dirname(file))
88
- open(file, 'wb') {|f| f.write(content)}
89
- end
90
-
91
- def exec(script, *args)
92
- script = File.dirname(__FILE__) + '/../../bin/' + script
93
- ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT'])
94
- system(ruby, script, *args)
95
- end
96
- end
@@ -1,1733 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require File.dirname(__FILE__) + '/../test_helper'
3
-
4
- class ExtendTest < MiniTest::Test
5
- def test_basic
6
- assert_equal <<CSS, render(<<SCSS)
7
- .foo, .bar {
8
- a: b; }
9
- CSS
10
- .foo {a: b}
11
- .bar {@extend .foo}
12
- SCSS
13
-
14
- assert_equal <<CSS, render(<<SCSS)
15
- .foo, .bar {
16
- a: b; }
17
- CSS
18
- .bar {@extend .foo}
19
- .foo {a: b}
20
- SCSS
21
-
22
- assert_equal <<CSS, render(<<SCSS)
23
- .foo, .bar {
24
- a: b; }
25
-
26
- .bar {
27
- c: d; }
28
- CSS
29
- .foo {a: b}
30
- .bar {c: d; @extend .foo}
31
- SCSS
32
-
33
- assert_equal <<CSS, render(<<SCSS)
34
- .foo, .bar {
35
- a: b; }
36
-
37
- .bar {
38
- c: d; }
39
- CSS
40
- .foo {a: b}
41
- .bar {@extend .foo; c: d}
42
- SCSS
43
- end
44
-
45
- def test_indented_syntax
46
- assert_equal <<CSS, render(<<SASS, :syntax => :sass)
47
- .foo, .bar {
48
- a: b; }
49
- CSS
50
- .foo
51
- a: b
52
- .bar
53
- @extend .foo
54
- SASS
55
-
56
- assert_equal <<CSS, render(<<SASS, :syntax => :sass)
57
- .foo, .bar {
58
- a: b; }
59
- CSS
60
- .foo
61
- a: b
62
- .bar
63
- @extend \#{".foo"}
64
- SASS
65
- end
66
-
67
- def test_multiple_targets
68
- assert_equal <<CSS, render(<<SCSS)
69
- .foo, .bar {
70
- a: b; }
71
-
72
- .blip .foo, .blip .bar {
73
- c: d; }
74
- CSS
75
- .foo {a: b}
76
- .bar {@extend .foo}
77
- .blip .foo {c: d}
78
- SCSS
79
- end
80
-
81
- def test_multiple_extendees
82
- assert_equal <<CSS, render(<<SCSS)
83
- .foo, .baz {
84
- a: b; }
85
-
86
- .bar, .baz {
87
- c: d; }
88
- CSS
89
- .foo {a: b}
90
- .bar {c: d}
91
- .baz {@extend .foo; @extend .bar}
92
- SCSS
93
- end
94
-
95
- def test_multiple_extends_with_single_extender_and_single_target
96
- assert_extends('.foo .bar', '.baz {@extend .foo; @extend .bar}',
97
- '.foo .bar, .baz .bar, .foo .baz, .baz .baz')
98
- assert_extends '.foo.bar', '.baz {@extend .foo; @extend .bar}', '.foo.bar, .baz'
99
- end
100
-
101
- def test_multiple_extends_with_multiple_extenders_and_single_target
102
- assert_equal <<CSS, render(<<SCSS)
103
- .foo .bar, .baz .bar, .foo .bang, .baz .bang {
104
- a: b; }
105
- CSS
106
- .foo .bar {a: b}
107
- .baz {@extend .foo}
108
- .bang {@extend .bar}
109
- SCSS
110
-
111
- assert_equal <<CSS, render(<<SCSS)
112
- .foo.bar, .bar.baz, .baz.bang, .foo.bang {
113
- a: b; }
114
- CSS
115
- .foo.bar {a: b}
116
- .baz {@extend .foo}
117
- .bang {@extend .bar}
118
- SCSS
119
- end
120
-
121
- def test_chained_extends
122
- assert_equal <<CSS, render(<<SCSS)
123
- .foo, .bar, .baz, .bip {
124
- a: b; }
125
- CSS
126
- .foo {a: b}
127
- .bar {@extend .foo}
128
- .baz {@extend .bar}
129
- .bip {@extend .bar}
130
- SCSS
131
- end
132
-
133
- def test_dynamic_extendee
134
- assert_extends '.foo', '.bar {@extend #{".foo"}}', '.foo, .bar'
135
- assert_extends('[baz^="blip12px"]', '.bar {@extend [baz^="blip#{12px}"]}',
136
- '[baz^="blip12px"], .bar')
137
- end
138
-
139
- def test_nested_target
140
- assert_extends '.foo .bar', '.baz {@extend .bar}', '.foo .bar, .foo .baz'
141
- end
142
-
143
- def test_target_with_child
144
- assert_extends '.foo .bar', '.baz {@extend .foo}', '.foo .bar, .baz .bar'
145
- end
146
-
147
- def test_class_unification
148
- assert_unification '.foo.bar', '.baz {@extend .foo}', '.foo.bar, .bar.baz'
149
- assert_unification '.foo.baz', '.baz {@extend .foo}', '.baz'
150
- end
151
-
152
- def test_id_unification
153
- assert_unification '.foo.bar', '#baz {@extend .foo}', '.foo.bar, .bar#baz'
154
- assert_unification '.foo#baz', '#baz {@extend .foo}', '#baz'
155
-
156
- assert_extend_doesnt_match('#bar', '.foo', :failed_to_unify, 2) do
157
- render_unification '.foo#baz', '#bar {@extend .foo}'
158
- end
159
- end
160
-
161
- def test_universal_unification_with_simple_target
162
- assert_unification '.foo', '* {@extend .foo}', '.foo, *'
163
- assert_unification '.foo', '*|* {@extend .foo}', '.foo, *|*'
164
- assert_unification '.foo.bar', '* {@extend .foo}', '.bar'
165
- assert_unification '.foo.bar', '*|* {@extend .foo}', '.bar'
166
- assert_unification '.foo.bar', 'ns|* {@extend .foo}', '.foo.bar, ns|*.bar'
167
- end
168
-
169
- def test_universal_unification_with_namespaceless_universal_target
170
- assert_extend_doesnt_match('ns|*', '.foo', :failed_to_unify, 2) do
171
- render_unification '*.foo', 'ns|* {@extend .foo}'
172
- end
173
-
174
- assert_unification '*.foo', '* {@extend .foo}', '*'
175
- assert_unification '*.foo', '*|* {@extend .foo}', '*'
176
- assert_unification '*|*.foo', '* {@extend .foo}', '*|*.foo, *'
177
- assert_unification '*|*.foo', '*|* {@extend .foo}', '*|*'
178
- assert_unification '*|*.foo', 'ns|* {@extend .foo}', '*|*.foo, ns|*'
179
- end
180
-
181
- def test_universal_unification_with_namespaced_universal_target
182
- assert_extend_doesnt_match('*', '.foo', :failed_to_unify, 2) do
183
- render_unification 'ns|*.foo', '* {@extend .foo}'
184
- end
185
-
186
- assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
187
- render_unification 'ns1|*.foo', 'ns2|* {@extend .foo}'
188
- end
189
-
190
- assert_unification 'ns|*.foo', '*|* {@extend .foo}', 'ns|*'
191
- assert_unification 'ns|*.foo', 'ns|* {@extend .foo}', 'ns|*'
192
- end
193
-
194
- def test_universal_unification_with_namespaceless_element_target
195
- assert_extend_doesnt_match('ns|*', '.foo', :failed_to_unify, 2) do
196
- render_unification 'a.foo', 'ns|* {@extend .foo}'
197
- end
198
-
199
- assert_unification 'a.foo', '* {@extend .foo}', 'a'
200
- assert_unification 'a.foo', '*|* {@extend .foo}', 'a'
201
- assert_unification '*|a.foo', '* {@extend .foo}', '*|a.foo, a'
202
- assert_unification '*|a.foo', '*|* {@extend .foo}', '*|a'
203
- assert_unification '*|a.foo', 'ns|* {@extend .foo}', '*|a.foo, ns|a'
204
- end
205
-
206
- def test_universal_unification_with_namespaced_element_target
207
- assert_extend_doesnt_match('*', '.foo', :failed_to_unify, 2) do
208
- render_unification 'ns|a.foo', '* {@extend .foo}'
209
- end
210
-
211
- assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
212
- render_unification 'ns1|a.foo', 'ns2|* {@extend .foo}'
213
- end
214
-
215
- assert_unification 'ns|a.foo', '*|* {@extend .foo}', 'ns|a'
216
- assert_unification 'ns|a.foo', 'ns|* {@extend .foo}', 'ns|a'
217
- end
218
-
219
- def test_element_unification_with_simple_target
220
- assert_unification '.foo', 'a {@extend .foo}', '.foo, a'
221
- assert_unification '.foo.bar', 'a {@extend .foo}', '.foo.bar, a.bar'
222
- assert_unification '.foo.bar', '*|a {@extend .foo}', '.foo.bar, *|a.bar'
223
- assert_unification '.foo.bar', 'ns|a {@extend .foo}', '.foo.bar, ns|a.bar'
224
- end
225
-
226
- def test_element_unification_with_namespaceless_universal_target
227
- assert_extend_doesnt_match('ns|a', '.foo', :failed_to_unify, 2) do
228
- render_unification '*.foo', 'ns|a {@extend .foo}'
229
- end
230
-
231
- assert_unification '*.foo', 'a {@extend .foo}', '*.foo, a'
232
- assert_unification '*.foo', '*|a {@extend .foo}', '*.foo, a'
233
- assert_unification '*|*.foo', 'a {@extend .foo}', '*|*.foo, a'
234
- assert_unification '*|*.foo', '*|a {@extend .foo}', '*|*.foo, *|a'
235
- assert_unification '*|*.foo', 'ns|a {@extend .foo}', '*|*.foo, ns|a'
236
- end
237
-
238
- def test_element_unification_with_namespaced_universal_target
239
- assert_extend_doesnt_match('a', '.foo', :failed_to_unify, 2) do
240
- render_unification 'ns|*.foo', 'a {@extend .foo}'
241
- end
242
-
243
- assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
244
- render_unification 'ns1|*.foo', 'ns2|a {@extend .foo}'
245
- end
246
-
247
- assert_unification 'ns|*.foo', '*|a {@extend .foo}', 'ns|*.foo, ns|a'
248
- assert_unification 'ns|*.foo', 'ns|a {@extend .foo}', 'ns|*.foo, ns|a'
249
- end
250
-
251
- def test_element_unification_with_namespaceless_element_target
252
- assert_extend_doesnt_match('ns|a', '.foo', :failed_to_unify, 2) do
253
- render_unification 'a.foo', 'ns|a {@extend .foo}'
254
- end
255
-
256
- assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do
257
- render_unification 'a.foo', 'h1 {@extend .foo}'
258
- end
259
-
260
- assert_unification 'a.foo', 'a {@extend .foo}', 'a'
261
- assert_unification 'a.foo', '*|a {@extend .foo}', 'a'
262
- assert_unification '*|a.foo', 'a {@extend .foo}', '*|a.foo, a'
263
- assert_unification '*|a.foo', '*|a {@extend .foo}', '*|a'
264
- assert_unification '*|a.foo', 'ns|a {@extend .foo}', '*|a.foo, ns|a'
265
- end
266
-
267
- def test_element_unification_with_namespaced_element_target
268
- assert_extend_doesnt_match('a', '.foo', :failed_to_unify, 2) do
269
- render_unification 'ns|a.foo', 'a {@extend .foo}'
270
- end
271
-
272
- assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
273
- render_unification 'ns1|a.foo', 'ns2|a {@extend .foo}'
274
- end
275
-
276
- assert_unification 'ns|a.foo', '*|a {@extend .foo}', 'ns|a'
277
- assert_unification 'ns|a.foo', 'ns|a {@extend .foo}', 'ns|a'
278
- end
279
-
280
- def test_attribute_unification
281
- assert_unification '[foo=bar].baz', '[foo=baz] {@extend .baz}', '[foo=bar].baz, [foo=bar][foo=baz]'
282
- assert_unification '[foo=bar].baz', '[foo^=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][foo^=bar]'
283
- assert_unification '[foo=bar].baz', '[foot=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][foot=bar]'
284
- assert_unification '[foo=bar].baz', '[ns|foo=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][ns|foo=bar]'
285
- assert_unification '%-a [foo=bar].bar', '[foo=bar] {@extend .bar}', '-a [foo=bar]'
286
- end
287
-
288
- def test_pseudo_unification
289
- assert_unification ':foo.baz', ':foo(2n+1) {@extend .baz}', ':foo.baz, :foo:foo(2n+1)'
290
- assert_unification ':foo.baz', '::foo {@extend .baz}', ':foo.baz, :foo::foo'
291
-
292
- assert_extend_doesnt_match('::bar', '.baz', :failed_to_unify, 2) do
293
- render_unification '::foo.baz', '::bar {@extend .baz}'
294
- end
295
-
296
- assert_extend_doesnt_match('::foo(2n+1)', '.baz', :failed_to_unify, 2) do
297
- render_unification '::foo.baz', '::foo(2n+1) {@extend .baz}'
298
- end
299
-
300
- assert_unification '::foo.baz', '::foo {@extend .baz}', '::foo'
301
- assert_unification '::foo(2n+1).baz', '::foo(2n+1) {@extend .baz}', '::foo(2n+1)'
302
- assert_unification ':foo.baz', ':bar {@extend .baz}', ':foo.baz, :foo:bar'
303
- assert_unification '.baz:foo', ':after {@extend .baz}', '.baz:foo, :foo:after'
304
- assert_unification '.baz:after', ':foo {@extend .baz}', '.baz:after, :foo:after'
305
- assert_unification ':foo.baz', ':foo {@extend .baz}', ':foo'
306
- end
307
-
308
- def test_pseudoelement_remains_at_end_of_selector
309
- assert_extends '.foo::bar', '.baz {@extend .foo}', '.foo::bar, .baz::bar'
310
- assert_extends 'a.foo::bar', '.baz {@extend .foo}', 'a.foo::bar, a.baz::bar'
311
- end
312
-
313
- def test_pseudoclass_remains_at_end_of_selector
314
- assert_extends '.foo:bar', '.baz {@extend .foo}', '.foo:bar, .baz:bar'
315
- assert_extends 'a.foo:bar', '.baz {@extend .foo}', 'a.foo:bar, a.baz:bar'
316
- end
317
-
318
- def test_not_remains_at_end_of_selector
319
- assert_extends '.foo:not(.bar)', '.baz {@extend .foo}', '.foo:not(.bar), .baz:not(.bar)'
320
- end
321
-
322
- def test_pseudoelement_goes_lefter_than_pseudoclass
323
- assert_extends '.foo::bar', '.baz:bang {@extend .foo}', '.foo::bar, .baz:bang::bar'
324
- assert_extends '.foo:bar', '.baz::bang {@extend .foo}', '.foo:bar, .baz:bar::bang'
325
- end
326
-
327
- def test_pseudoelement_goes_lefter_than_not
328
- assert_extends '.foo::bar', '.baz:not(.bang) {@extend .foo}', '.foo::bar, .baz:not(.bang)::bar'
329
- assert_extends '.foo:not(.bang)', '.baz::bar {@extend .foo}', '.foo:not(.bang), .baz:not(.bang)::bar'
330
- end
331
-
332
- def test_negation_unification
333
- assert_extends ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
334
- # Unifying to :not(.foo) here would reduce the specificity of the original selector.
335
- assert_extends ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo).baz, :not(.foo)'
336
- end
337
-
338
- def test_prefixed_pseudoclass_unification
339
- assert_unification(
340
- ':nth-child(2n+1 of .foo).baz',
341
- ':nth-child(2n of .foo) {@extend .baz}',
342
- ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n of .foo)')
343
-
344
- assert_unification(
345
- ':nth-child(2n+1 of .foo).baz',
346
- ':nth-child(2n+1 of .bar) {@extend .baz}',
347
- ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n+1 of .bar)')
348
-
349
- assert_unification(
350
- ':nth-child(2n+1 of .foo).baz',
351
- ':nth-child(2n+1 of .foo) {@extend .baz}',
352
- ':nth-child(2n+1 of .foo)')
353
- end
354
-
355
- def test_extend_into_not
356
- assert_extends(':not(.foo)', '.x {@extend .foo}', ':not(.foo):not(.x)')
357
- assert_extends(':not(.foo.bar)', '.x {@extend .bar}', ':not(.foo.bar):not(.foo.x)')
358
- assert_extends(
359
- ':not(.foo.bar, .baz.bar)',
360
- '.x {@extend .bar}',
361
- ':not(.foo.bar, .foo.x, .baz.bar, .baz.x)')
362
- end
363
-
364
- def test_extend_into_mergeable_pseudoclasses
365
- assert_extends(':matches(.foo)', '.x {@extend .foo}', ':matches(.foo, .x)')
366
- assert_extends(':matches(.foo.bar)', '.x {@extend .bar}', ':matches(.foo.bar, .foo.x)')
367
- assert_extends(
368
- ':matches(.foo.bar, .baz.bar)',
369
- '.x {@extend .bar}',
370
- ':matches(.foo.bar, .foo.x, .baz.bar, .baz.x)')
371
-
372
- assert_extends(':-moz-any(.foo)', '.x {@extend .foo}', ':-moz-any(.foo, .x)')
373
- assert_extends(':current(.foo)', '.x {@extend .foo}', ':current(.foo, .x)')
374
- assert_extends(':has(.foo)', '.x {@extend .foo}', ':has(.foo, .x)')
375
- assert_extends(':host(.foo)', '.x {@extend .foo}', ':host(.foo, .x)')
376
- assert_extends(':host-context(.foo)', '.x {@extend .foo}', ':host-context(.foo, .x)')
377
- assert_extends(':nth-child(n of .foo)', '.x {@extend .foo}', ':nth-child(n of .foo, .x)')
378
- assert_extends(
379
- ':nth-last-child(n of .foo)',
380
- '.x {@extend .foo}',
381
- ':nth-last-child(n of .foo, .x)')
382
- end
383
-
384
- def test_complex_extend_into_pseudoclass
385
- # Unlike other selectors, we don't allow complex selectors to be
386
- # added to `:not` if they weren't there before. At time of
387
- # writing, most browsers don't support that and will throw away
388
- # the entire selector if it exists.
389
- #assert_extends(':not(.bar)', '.x .y {@extend .bar}', ':not(.bar)')
390
-
391
- # If the `:not()` already has a complex selector, we won't break
392
- # anything by adding a new one.
393
- assert_extends(':not(.baz .bar)', '.x .y {@extend .bar}',
394
- ':not(.baz .bar):not(.baz .x .y):not(.x .baz .y)')
395
-
396
- # If the `:not()` would only contain complex selectors, there's no
397
- # harm in letting it continue to exist.
398
- assert_extends(':not(%bar)', '.x .y {@extend %bar}', ':not(.x .y)')
399
-
400
- assert_extends(':matches(.bar)', '.x .y {@extend .bar}', ':matches(.bar, .x .y)')
401
- assert_extends(':current(.bar)', '.x .y {@extend .bar}', ':current(.bar, .x .y)')
402
- assert_extends(':has(.bar)', '.x .y {@extend .bar}', ':has(.bar, .x .y)')
403
- assert_extends(':host(.bar)', '.x .y {@extend .bar}', ':host(.bar, .x .y)')
404
- assert_extends(':host-context(.bar)', '.x .y {@extend .bar}', ':host-context(.bar, .x .y)')
405
- assert_extends(
406
- ':-moz-any(.bar)',
407
- '.x .y {@extend .bar}',
408
- ':-moz-any(.bar, .x .y)')
409
- assert_extends(
410
- ':nth-child(n of .bar)',
411
- '.x .y {@extend .bar}',
412
- ':nth-child(n of .bar, .x .y)')
413
- assert_extends(
414
- ':nth-last-child(n of .bar)',
415
- '.x .y {@extend .bar}',
416
- ':nth-last-child(n of .bar, .x .y)')
417
- end
418
-
419
- def test_extend_over_selector_pseudoclass
420
- assert_extends(':not(.foo)', '.x {@extend :not(.foo)}', ':not(.foo), .x')
421
- assert_extends(
422
- ':matches(.foo, .bar)',
423
- '.x {@extend :matches(.foo, .bar)}',
424
- ':matches(.foo, .bar), .x')
425
- end
426
-
427
- def test_matches_within_not
428
- assert_extends(
429
- ':not(.foo, .bar)',
430
- ':matches(.x, .y) {@extend .foo}',
431
- ':not(.foo, .x, .y, .bar)')
432
- end
433
-
434
- def test_pseudoclasses_merge
435
- assert_extends(':matches(.foo)', ':matches(.bar) {@extend .foo}', ':matches(.foo, .bar)')
436
- assert_extends(':-moz-any(.foo)', ':-moz-any(.bar) {@extend .foo}', ':-moz-any(.foo, .bar)')
437
- assert_extends(':current(.foo)', ':current(.bar) {@extend .foo}', ':current(.foo, .bar)')
438
- assert_extends(
439
- ':nth-child(n of .foo)',
440
- ':nth-child(n of .bar) {@extend .foo}',
441
- ':nth-child(n of .foo, .bar)')
442
- assert_extends(
443
- ':nth-last-child(n of .foo)',
444
- ':nth-last-child(n of .bar) {@extend .foo}',
445
- ':nth-last-child(n of .foo, .bar)')
446
- end
447
-
448
- def test_nesting_pseudoclasses_merge
449
- assert_extends(':has(.foo)', ':has(.bar) {@extend .foo}', ':has(.foo, :has(.bar))')
450
- assert_extends(':host(.foo)', ':host(.bar) {@extend .foo}', ':host(.foo, :host(.bar))')
451
- assert_extends(
452
- ':host-context(.foo)',
453
- ':host-context(.bar) {@extend .foo}',
454
- ':host-context(.foo, :host-context(.bar))')
455
- end
456
-
457
- def test_not_unifies_with_unique_values
458
- assert_unification('foo', ':not(bar) {@extend foo}', ':not(bar)')
459
- assert_unification('#foo', ':not(#bar) {@extend #foo}', ':not(#bar)')
460
- end
461
-
462
- def test_not_adds_no_specificity
463
- assert_specificity_equals(':not(.foo)', '.foo')
464
- end
465
-
466
- def test_matches_has_a_specificity_range
467
- # `:matches(.foo, #bar)` has minimum specificity equal to that of `.foo`,
468
- # which means `:matches(.foo, #bar) .a` can have less specificity than
469
- # `#b.a`. Thus the selector generated by `#b.a` should be preserved.
470
- assert_equal <<CSS, render(<<SCSS)
471
- :matches(.foo, #bar) .a, :matches(.foo, #bar) #b.a {
472
- a: b; }
473
- CSS
474
- :matches(.foo, #bar) %x {a: b}
475
- .a {@extend %x}
476
- #b.a {@extend %x}
477
- SCSS
478
-
479
- # `:matches(.foo, #bar)` has maximum specificity equal to that of `#bar`,
480
- # which means `:matches(.foo, #bar).b` can have greater specificity than `.a
481
- # .b`. Thus the selector generated by `:matches(.foo, #bar).b` should be
482
- # preserved.
483
- assert_equal <<CSS, render(<<SCSS)
484
- .a .b, .a .b:matches(.foo, #bar) {
485
- a: b; }
486
- CSS
487
- .a %x {a: b}
488
- .b {@extend %x}
489
- .b:matches(.foo, #bar) {@extend %x}
490
- SCSS
491
- end
492
-
493
- def test_extend_into_not_and_normal_extend
494
- assert_equal <<CSS, render(<<SCSS)
495
- .x:not(.y):not(.bar), .foo:not(.y):not(.bar) {
496
- a: b; }
497
- CSS
498
- .x:not(.y) {a: b}
499
- .foo {@extend .x}
500
- .bar {@extend .y}
501
- SCSS
502
- end
503
-
504
- def test_extend_into_matches_and_normal_extend
505
- assert_equal <<CSS, render(<<SCSS)
506
- .x:matches(.y, .bar), .foo:matches(.y, .bar) {
507
- a: b; }
508
- CSS
509
- .x:matches(.y) {a: b}
510
- .foo {@extend .x}
511
- .bar {@extend .y}
512
- SCSS
513
- end
514
-
515
- def test_multilayer_pseudoclass_extend
516
- assert_equal <<CSS, render(<<SCSS)
517
- :matches(.x, .foo, .bar) {
518
- a: b; }
519
- CSS
520
- :matches(.x) {a: b}
521
- .foo {@extend .x}
522
- .bar {@extend .foo}
523
- SCSS
524
- end
525
-
526
- def test_root_only_allowed_at_root
527
- assert_extends(':root .foo', '.bar .baz {@extend .foo}',
528
- ':root .foo, :root .bar .baz')
529
- assert_extends('.foo:root .bar', '.baz:root .bang {@extend .bar}',
530
- '.foo:root .bar, .baz.foo:root .bang')
531
- assert_extends('html:root .bar', 'xml:root .bang {@extend .bar}', 'html:root .bar')
532
- assert_extends('.foo:root > .bar .x', '.baz:root .bang .y {@extend .x}',
533
- '.foo:root > .bar .x, .baz.foo:root > .bar .bang .y')
534
- end
535
-
536
- def test_comma_extendee
537
- assert_equal <<CSS, render(<<SCSS)
538
- .foo, .baz {
539
- a: b; }
540
-
541
- .bar, .baz {
542
- c: d; }
543
- CSS
544
- .foo {a: b}
545
- .bar {c: d}
546
- .baz {@extend .foo, .bar}
547
- SCSS
548
- end
549
-
550
- def test_redundant_selector_elimination
551
- assert_equal <<CSS, render(<<SCSS)
552
- .foo.bar, .x, .y {
553
- a: b; }
554
- CSS
555
- .foo.bar {a: b}
556
- .x {@extend .foo, .bar}
557
- .y {@extend .foo, .bar}
558
- SCSS
559
- end
560
-
561
- def test_nested_pseudo_selectors
562
- assert_equal <<CSS, render(<<SCSS)
563
- .foo .bar:not(.baz), .bang .bar:not(.baz) {
564
- a: b; }
565
- CSS
566
- .foo {
567
- .bar:not(.baz) {a: b}
568
- }
569
- .bang {@extend .foo}
570
- SCSS
571
- end
572
-
573
- ## Long Extendees
574
-
575
- def test_long_extendee
576
- assert_warning(<<WARNING) {assert_extends '.foo.bar', '.baz {@extend .foo.bar}', '.foo.bar, .baz'}
577
- DEPRECATION WARNING on line 2 of test_long_extendee_inline.scss:
578
- Extending a compound selector, .foo.bar, is deprecated and will not be supported in a future release.
579
- See https://github.com/sass/sass/issues/1599 for details.
580
- WARNING
581
- end
582
-
583
- def test_long_extendee_requires_all_selectors
584
- silence_warnings do
585
- assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do
586
- render_extends '.foo', '.baz {@extend .foo.bar}'
587
- end
588
- end
589
- end
590
-
591
- def test_long_extendee_matches_supersets
592
- silence_warnings {assert_extends '.foo.bar.bap', '.baz {@extend .foo.bar}', '.foo.bar.bap, .bap.baz'}
593
- end
594
-
595
- def test_long_extendee_runs_unification
596
- silence_warnings {assert_extends 'ns|*.foo.bar', '*|a.baz {@extend .foo.bar}', 'ns|*.foo.bar, ns|a.baz'}
597
- end
598
-
599
- ## Long Extenders
600
-
601
- def test_long_extender
602
- assert_extends '.foo.bar', '.baz.bang {@extend .foo}', '.foo.bar, .bar.baz.bang'
603
- end
604
-
605
- def test_long_extender_runs_unification
606
- assert_extends 'ns|*.foo.bar', '*|a.baz {@extend .foo}', 'ns|*.foo.bar, ns|a.bar.baz'
607
- end
608
-
609
- def test_long_extender_aborts_unification
610
- assert_extend_doesnt_match('h1.baz', '.foo', :failed_to_unify, 2) do
611
- render_extends 'a.foo#bar', 'h1.baz {@extend .foo}'
612
- end
613
-
614
- assert_extend_doesnt_match('.bang#baz', '.foo', :failed_to_unify, 2) do
615
- render_extends 'a.foo#bar', '.bang#baz {@extend .foo}'
616
- end
617
- end
618
-
619
- ## Nested Extenders
620
-
621
- def test_nested_extender
622
- assert_extends '.foo', 'foo bar {@extend .foo}', '.foo, foo bar'
623
- end
624
-
625
- def test_nested_extender_runs_unification
626
- assert_extends '.foo.bar', 'foo bar {@extend .foo}', '.foo.bar, foo bar.bar'
627
- end
628
-
629
- def test_nested_extender_aborts_unification
630
- assert_extend_doesnt_match('foo bar', '.foo', :failed_to_unify, 2) do
631
- render_extends 'baz.foo', 'foo bar {@extend .foo}'
632
- end
633
- end
634
-
635
- def test_nested_extender_alternates_parents
636
- assert_extends('.baz .bip .foo', 'foo .grank bar {@extend .foo}',
637
- '.baz .bip .foo, .baz .bip foo .grank bar, foo .grank .baz .bip bar')
638
- end
639
-
640
- def test_nested_extender_unifies_identical_parents
641
- assert_extends('.baz .bip .foo', '.baz .bip bar {@extend .foo}',
642
- '.baz .bip .foo, .baz .bip bar')
643
- end
644
-
645
- def test_nested_extender_unifies_common_substring
646
- assert_extends('.baz .bip .bap .bink .foo', '.brat .bip .bap bar {@extend .foo}',
647
- '.baz .bip .bap .bink .foo, .baz .brat .bip .bap .bink bar, .brat .baz .bip .bap .bink bar')
648
- end
649
-
650
- def test_nested_extender_unifies_common_subseq
651
- assert_extends('.a .x .b .y .foo', '.a .n .b .m bar {@extend .foo}',
652
- '.a .x .b .y .foo, .a .x .n .b .y .m bar, .a .n .x .b .y .m bar, .a .x .n .b .m .y bar, .a .n .x .b .m .y bar')
653
- end
654
-
655
- def test_nested_extender_chooses_first_subseq
656
- assert_extends('.a .b .c .d .foo', '.c .d .a .b .bar {@extend .foo}',
657
- '.a .b .c .d .foo, .a .b .c .d .a .b .bar')
658
- end
659
-
660
- def test_nested_extender_counts_extended_subselectors
661
- assert_extends('.a .bip.bop .foo', '.b .bip .bar {@extend .foo}',
662
- '.a .bip.bop .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')
663
- end
664
-
665
- def test_nested_extender_counts_extended_superselectors
666
- assert_extends('.a .bip .foo', '.b .bip.bop .bar {@extend .foo}',
667
- '.a .bip .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')
668
- end
669
-
670
- def test_nested_extender_with_child_selector
671
- assert_extends '.baz .foo', 'foo > bar {@extend .foo}', '.baz .foo, .baz foo > bar'
672
- end
673
-
674
- def test_nested_extender_finds_common_selectors_around_child_selector
675
- assert_extends 'a > b c .c1', 'a c .c2 {@extend .c1}', 'a > b c .c1, a > b c .c2'
676
- assert_extends 'a > b c .c1', 'b c .c2 {@extend .c1}', 'a > b c .c1, a > b c .c2'
677
- end
678
-
679
- def test_nested_extender_doesnt_find_common_selectors_around_adjacent_sibling_selector
680
- assert_extends 'a + b c .c1', 'a c .c2 {@extend .c1}', 'a + b c .c1, a + b a c .c2, a a + b c .c2'
681
- assert_extends 'a + b c .c1', 'a b .c2 {@extend .c1}', 'a + b c .c1, a a + b c .c2'
682
- assert_extends 'a + b c .c1', 'b c .c2 {@extend .c1}', 'a + b c .c1, a + b c .c2'
683
- end
684
-
685
- def test_nested_extender_doesnt_find_common_selectors_around_sibling_selector
686
- assert_extends 'a ~ b c .c1', 'a c .c2 {@extend .c1}', 'a ~ b c .c1, a ~ b a c .c2, a a ~ b c .c2'
687
- assert_extends 'a ~ b c .c1', 'a b .c2 {@extend .c1}', 'a ~ b c .c1, a a ~ b c .c2'
688
- assert_extends 'a ~ b c .c1', 'b c .c2 {@extend .c1}', 'a ~ b c .c1, a ~ b c .c2'
689
- end
690
-
691
- def test_nested_extender_doesnt_find_common_selectors_around_reference_selector
692
- silence_warnings {assert_extends 'a /for/ b c .c1', 'a c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2'}
693
- silence_warnings {assert_extends 'a /for/ b c .c1', 'a b .c2 {@extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'}
694
- silence_warnings {assert_extends 'a /for/ b c .c1', 'b c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'}
695
- end
696
-
697
- def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
698
- assert_extends('.bip > .bap .foo', '.grip > .bap .bar {@extend .foo}',
699
- '.bip > .bap .foo, .bip > .bap .grip > .bap .bar, .grip > .bap .bip > .bap .bar')
700
- assert_extends('.bap > .bip .foo', '.bap > .grip .bar {@extend .foo}',
701
- '.bap > .bip .foo, .bap > .bip .bap > .grip .bar, .bap > .grip .bap > .bip .bar')
702
- end
703
-
704
- def test_nested_extender_with_child_selector_unifies
705
- assert_extends '.baz.foo', 'foo > bar {@extend .foo}', '.baz.foo, foo > bar.baz'
706
-
707
- assert_equal <<CSS, render(<<SCSS)
708
- .baz > .foo, .baz > .bar {
709
- a: b; }
710
- CSS
711
- .baz > {
712
- .foo {a: b}
713
- .bar {@extend .foo}
714
- }
715
- SCSS
716
-
717
- assert_equal <<CSS, render(<<SCSS)
718
- .foo .bar, .foo > .baz {
719
- a: b; }
720
- CSS
721
- .foo {
722
- .bar {a: b}
723
- > .baz {@extend .bar}
724
- }
725
- SCSS
726
- end
727
-
728
- def test_nested_extender_with_early_child_selector
729
- assert_equal <<CSS, render(<<SCSS)
730
- .foo .bar, .foo .bip > .baz {
731
- a: b; }
732
- CSS
733
- .foo {
734
- .bar {a: b}
735
- .bip > .baz {@extend .bar}
736
- }
737
- SCSS
738
-
739
- assert_equal <<CSS, render(<<SCSS)
740
- .foo .bip .bar, .foo .bip .foo > .baz {
741
- a: b; }
742
- CSS
743
- .foo {
744
- .bip .bar {a: b}
745
- > .baz {@extend .bar}
746
- }
747
- SCSS
748
-
749
- assert_extends '.foo > .bar', '.bip + .baz {@extend .bar}', '.foo > .bar, .foo > .bip + .baz'
750
- assert_extends '.foo + .bar', '.bip > .baz {@extend .bar}', '.foo + .bar, .bip > .foo + .baz'
751
- assert_extends '.foo > .bar', '.bip > .baz {@extend .bar}', '.foo > .bar, .bip.foo > .baz'
752
- end
753
-
754
- def test_nested_extender_with_trailing_child_selector
755
- assert_raises(Sass::SyntaxError, "bar > can't extend: invalid selector") do
756
- render("bar > {@extend .baz}")
757
- end
758
- end
759
-
760
- def test_nested_extender_with_sibling_selector
761
- assert_extends '.baz .foo', 'foo + bar {@extend .foo}', '.baz .foo, .baz foo + bar'
762
- end
763
-
764
- def test_nested_extender_with_hacky_selector
765
- assert_extends('.baz .foo', 'foo + > > + bar {@extend .foo}',
766
- '.baz .foo, .baz foo + > > + bar, foo .baz + > > + bar')
767
- assert_extends '.baz .foo', '> > bar {@extend .foo}', '.baz .foo, > > .baz bar'
768
- end
769
-
770
- def test_nested_extender_merges_with_same_selector
771
- assert_equal <<CSS, render(<<SCSS)
772
- .foo .bar, .foo .baz {
773
- a: b; }
774
- CSS
775
- .foo {
776
- .bar {a: b}
777
- .baz {@extend .bar} }
778
- SCSS
779
- end
780
-
781
- def test_nested_extender_with_child_selector_merges_with_same_selector
782
- assert_extends('.foo > .bar .baz', '.foo > .bar .bang {@extend .baz}',
783
- '.foo > .bar .baz, .foo > .bar .bang')
784
- end
785
-
786
- # Combinator Unification
787
-
788
- def test_combinator_unification_for_hacky_combinators
789
- assert_extends '.a > + x', '.b y {@extend x}', '.a > + x, .a .b > + y, .b .a > + y'
790
- assert_extends '.a x', '.b > + y {@extend x}', '.a x, .a .b > + y, .b .a > + y'
791
- assert_extends '.a > + x', '.b > + y {@extend x}', '.a > + x, .a .b > + y, .b .a > + y'
792
- assert_extends '.a ~ > + x', '.b > + y {@extend x}', '.a ~ > + x, .a .b ~ > + y, .b .a ~ > + y'
793
- assert_extends '.a + > x', '.b > + y {@extend x}', '.a + > x'
794
- assert_extends '.a + > x', '.b > + y {@extend x}', '.a + > x'
795
- assert_extends '.a ~ > + .b > x', '.c > + .d > y {@extend x}', '.a ~ > + .b > x, .a .c ~ > + .d.b > y, .c .a ~ > + .d.b > y'
796
- end
797
-
798
- def test_combinator_unification_double_tilde
799
- assert_extends '.a.b ~ x', '.a ~ y {@extend x}', '.a.b ~ x, .a.b ~ y'
800
- assert_extends '.a ~ x', '.a.b ~ y {@extend x}', '.a ~ x, .a.b ~ y'
801
- assert_extends '.a ~ x', '.b ~ y {@extend x}', '.a ~ x, .a ~ .b ~ y, .b ~ .a ~ y, .b.a ~ y'
802
- assert_extends 'a.a ~ x', 'b.b ~ y {@extend x}', 'a.a ~ x, a.a ~ b.b ~ y, b.b ~ a.a ~ y'
803
- end
804
-
805
- def test_combinator_unification_tilde_plus
806
- assert_extends '.a.b + x', '.a ~ y {@extend x}', '.a.b + x, .a.b + y'
807
- assert_extends '.a + x', '.a.b ~ y {@extend x}', '.a + x, .a.b ~ .a + y, .a.b + y'
808
- assert_extends '.a + x', '.b ~ y {@extend x}', '.a + x, .b ~ .a + y, .b.a + y'
809
- assert_extends 'a.a + x', 'b.b ~ y {@extend x}', 'a.a + x, b.b ~ a.a + y'
810
- assert_extends '.a.b ~ x', '.a + y {@extend x}', '.a.b ~ x, .a.b ~ .a + y, .a.b + y'
811
- assert_extends '.a ~ x', '.a.b + y {@extend x}', '.a ~ x, .a.b + y'
812
- assert_extends '.a ~ x', '.b + y {@extend x}', '.a ~ x, .a ~ .b + y, .a.b + y'
813
- assert_extends 'a.a ~ x', 'b.b + y {@extend x}', 'a.a ~ x, a.a ~ b.b + y'
814
- end
815
-
816
- def test_combinator_unification_angle_sibling
817
- assert_extends '.a > x', '.b ~ y {@extend x}', '.a > x, .a > .b ~ y'
818
- assert_extends '.a > x', '.b + y {@extend x}', '.a > x, .a > .b + y'
819
- assert_extends '.a ~ x', '.b > y {@extend x}', '.a ~ x, .b > .a ~ y'
820
- assert_extends '.a + x', '.b > y {@extend x}', '.a + x, .b > .a + y'
821
- end
822
-
823
- def test_combinator_unification_double_angle
824
- assert_extends '.a.b > x', '.b > y {@extend x}', '.a.b > x, .b.a > y'
825
- assert_extends '.a > x', '.a.b > y {@extend x}', '.a > x, .a.b > y'
826
- assert_extends '.a > x', '.b > y {@extend x}', '.a > x, .b.a > y'
827
- assert_extends 'a.a > x', 'b.b > y {@extend x}', 'a.a > x'
828
- end
829
-
830
- def test_combinator_unification_double_plus
831
- assert_extends '.a.b + x', '.b + y {@extend x}', '.a.b + x, .b.a + y'
832
- assert_extends '.a + x', '.a.b + y {@extend x}', '.a + x, .a.b + y'
833
- assert_extends '.a + x', '.b + y {@extend x}', '.a + x, .b.a + y'
834
- assert_extends 'a.a + x', 'b.b + y {@extend x}', 'a.a + x'
835
- end
836
-
837
- def test_combinator_unification_angle_space
838
- assert_extends '.a.b > x', '.a y {@extend x}', '.a.b > x, .a.b > y'
839
- assert_extends '.a > x', '.a.b y {@extend x}', '.a > x, .a.b .a > y'
840
- assert_extends '.a > x', '.b y {@extend x}', '.a > x, .b .a > y'
841
- assert_extends '.a.b x', '.a > y {@extend x}', '.a.b x, .a.b .a > y'
842
- assert_extends '.a x', '.a.b > y {@extend x}', '.a x, .a.b > y'
843
- assert_extends '.a x', '.b > y {@extend x}', '.a x, .a .b > y'
844
- end
845
-
846
- def test_combinator_unification_plus_space
847
- assert_extends '.a.b + x', '.a y {@extend x}', '.a.b + x, .a .a.b + y'
848
- assert_extends '.a + x', '.a.b y {@extend x}', '.a + x, .a.b .a + y'
849
- assert_extends '.a + x', '.b y {@extend x}', '.a + x, .b .a + y'
850
- assert_extends '.a.b x', '.a + y {@extend x}', '.a.b x, .a.b .a + y'
851
- assert_extends '.a x', '.a.b + y {@extend x}', '.a x, .a .a.b + y'
852
- assert_extends '.a x', '.b + y {@extend x}', '.a x, .a .b + y'
853
- end
854
-
855
- def test_combinator_unification_nested
856
- assert_extends '.a > .b + x', '.c > .d + y {@extend x}', '.a > .b + x, .c.a > .d.b + y'
857
- assert_extends '.a > .b + x', '.c > y {@extend x}', '.a > .b + x, .c.a > .b + y'
858
- end
859
-
860
- def test_combinator_unification_with_newlines
861
- assert_equal <<CSS, render(<<SCSS)
862
- .a >
863
- .b
864
- + x, .c.a > .d.b + y {
865
- a: b; }
866
- CSS
867
- .a >
868
- .b
869
- + x {a: b}
870
- .c
871
- > .d +
872
- y {@extend x}
873
- SCSS
874
- end
875
-
876
- # Loops
877
-
878
- def test_extend_self_loop
879
- assert_equal <<CSS, render(<<SCSS)
880
- .foo {
881
- a: b; }
882
- CSS
883
- .foo {a: b; @extend .foo}
884
- SCSS
885
- end
886
-
887
- def test_basic_extend_loop
888
- assert_equal <<CSS, render(<<SCSS)
889
- .foo, .bar {
890
- a: b; }
891
-
892
- .bar, .foo {
893
- c: d; }
894
- CSS
895
- .foo {a: b; @extend .bar}
896
- .bar {c: d; @extend .foo}
897
- SCSS
898
- end
899
-
900
- def test_three_level_extend_loop
901
- assert_equal <<CSS, render(<<SCSS)
902
- .foo, .baz, .bar {
903
- a: b; }
904
-
905
- .bar, .foo, .baz {
906
- c: d; }
907
-
908
- .baz, .bar, .foo {
909
- e: f; }
910
- CSS
911
- .foo {a: b; @extend .bar}
912
- .bar {c: d; @extend .baz}
913
- .baz {e: f; @extend .foo}
914
- SCSS
915
- end
916
-
917
- def test_nested_extend_loop
918
- assert_equal <<CSS, render(<<SCSS)
919
- .bar, .bar .foo {
920
- a: b; }
921
- .bar .foo {
922
- c: d; }
923
- CSS
924
- .bar {
925
- a: b;
926
- .foo {c: d; @extend .bar}
927
- }
928
- SCSS
929
- end
930
-
931
- def test_cross_loop
932
- # The first law of extend means the selector should stick around.
933
- assert_equal <<CSS, render(<<SCSS)
934
- .foo.bar, .foo, .bar {
935
- a: b; }
936
- CSS
937
- .foo.bar {a: b}
938
- .foo {@extend .bar}
939
- .bar {@extend .foo}
940
- SCSS
941
- end
942
-
943
- def test_multiple_extender_merges_with_superset_selector
944
- assert_equal <<CSS, render(<<SCSS)
945
- a.bar.baz, a.foo {
946
- a: b; }
947
- CSS
948
- .foo {@extend .bar; @extend .baz}
949
- a.bar.baz {a: b}
950
- SCSS
951
- end
952
-
953
- def test_control_flow_if
954
- assert_equal <<CSS, render(<<SCSS)
955
- .true, .also-true {
956
- color: green; }
957
-
958
- .false, .also-false {
959
- color: red; }
960
- CSS
961
- .true { color: green; }
962
- .false { color: red; }
963
- .also-true {
964
- @if true { @extend .true; }
965
- @else { @extend .false; }
966
- }
967
- .also-false {
968
- @if false { @extend .true; }
969
- @else { @extend .false; }
970
- }
971
- SCSS
972
- end
973
-
974
- def test_control_flow_for
975
- assert_equal <<CSS, render(<<SCSS)
976
- .base-0, .added {
977
- color: green; }
978
-
979
- .base-1, .added {
980
- display: block; }
981
-
982
- .base-2, .added {
983
- border: 1px solid blue; }
984
- CSS
985
- .base-0 { color: green; }
986
- .base-1 { display: block; }
987
- .base-2 { border: 1px solid blue; }
988
- .added {
989
- @for $i from 0 to 3 {
990
- @extend .base-\#{$i};
991
- }
992
- }
993
- SCSS
994
- end
995
-
996
- def test_control_flow_while
997
- assert_equal <<CSS, render(<<SCSS)
998
- .base-0, .added {
999
- color: green; }
1000
-
1001
- .base-1, .added {
1002
- display: block; }
1003
-
1004
- .base-2, .added {
1005
- border: 1px solid blue; }
1006
- CSS
1007
- .base-0 { color: green; }
1008
- .base-1 { display: block; }
1009
- .base-2 { border: 1px solid blue; }
1010
- .added {
1011
- $i : 0;
1012
- @while $i < 3 {
1013
- @extend .base-\#{$i};
1014
- $i : $i + 1;
1015
- }
1016
- }
1017
- SCSS
1018
- end
1019
-
1020
- def test_basic_placeholder_selector
1021
- assert_extends '%foo', '.bar {@extend %foo}', '.bar'
1022
- end
1023
-
1024
- def test_unused_placeholder_selector
1025
- assert_equal <<CSS, render(<<SCSS)
1026
- .baz {
1027
- color: blue; }
1028
- CSS
1029
- %foo {color: blue}
1030
- %bar {color: red}
1031
- .baz {@extend %foo}
1032
- SCSS
1033
- end
1034
-
1035
- def test_placeholder_descendant_selector
1036
- assert_extends '#context %foo a', '.bar {@extend %foo}', '#context .bar a'
1037
- end
1038
-
1039
- def test_semi_placeholder_selector
1040
- assert_equal <<CSS, render(<<SCSS)
1041
- .bar .baz {
1042
- color: blue; }
1043
- CSS
1044
- #context %foo, .bar .baz {color: blue}
1045
- SCSS
1046
- end
1047
-
1048
- def test_placeholder_selector_with_multiple_extenders
1049
- assert_equal <<CSS, render(<<SCSS)
1050
- .bar, .baz {
1051
- color: blue; }
1052
- CSS
1053
- %foo {color: blue}
1054
- .bar {@extend %foo}
1055
- .baz {@extend %foo}
1056
- SCSS
1057
- end
1058
-
1059
- def test_placeholder_selector_as_modifier
1060
- assert_extend_doesnt_match('div', '%foo', :failed_to_unify, 3) do
1061
- render(<<SCSS)
1062
- a%foo.baz {color: blue}
1063
- .bar {@extend %foo}
1064
- div {@extend %foo}
1065
- SCSS
1066
- end
1067
- end
1068
-
1069
- def test_placeholder_interpolation
1070
- assert_equal <<CSS, render(<<SCSS)
1071
- .bar {
1072
- color: blue; }
1073
- CSS
1074
- $foo: foo;
1075
-
1076
- %\#{$foo} {color: blue}
1077
- .bar {@extend %foo}
1078
- SCSS
1079
- end
1080
-
1081
- def test_placeholder_in_selector_pseudoclass
1082
- assert_equal <<CSS, render(<<SCSS)
1083
- :matches(.bar, .baz) {
1084
- color: blue; }
1085
- CSS
1086
- :matches(%foo) {color: blue}
1087
- .bar {@extend %foo}
1088
- .baz {@extend %foo}
1089
- SCSS
1090
- end
1091
-
1092
- def test_media_in_placeholder_selector
1093
- assert_equal <<CSS, render(<<SCSS)
1094
- .baz {
1095
- c: d; }
1096
- CSS
1097
- %foo {bar {@media screen {a: b}}}
1098
- .baz {c: d}
1099
- SCSS
1100
- end
1101
-
1102
- def test_extend_out_of_media
1103
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1104
- You may not @extend an outer selector from within @media.
1105
- You may only @extend selectors within the same directive.
1106
- From "@extend .foo" on line 3 of test_extend_out_of_media_inline.scss.
1107
- ERR
1108
- .foo {a: b}
1109
- @media screen {
1110
- .bar {@extend .foo}
1111
- }
1112
- SCSS
1113
- end
1114
-
1115
- def test_extend_out_of_unknown_directive
1116
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1117
- You may not @extend an outer selector from within @flooblehoof.
1118
- You may only @extend selectors within the same directive.
1119
- From "@extend .foo" on line 3 of test_extend_out_of_unknown_directive_inline.scss.
1120
- ERR
1121
- .foo {a: b}
1122
- @flooblehoof {
1123
- .bar {@extend .foo}
1124
- }
1125
- SCSS
1126
- end
1127
-
1128
- def test_extend_out_of_nested_directives
1129
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1130
- You may not @extend an outer selector from within @flooblehoof.
1131
- You may only @extend selectors within the same directive.
1132
- From "@extend .foo" on line 4 of test_extend_out_of_nested_directives_inline.scss.
1133
- ERR
1134
- @media screen {
1135
- .foo {a: b}
1136
- @flooblehoof {
1137
- .bar {@extend .foo}
1138
- }
1139
- }
1140
- SCSS
1141
- end
1142
-
1143
- def test_extend_within_media
1144
- assert_equal(<<CSS, render(<<SCSS))
1145
- @media screen {
1146
- .foo, .bar {
1147
- a: b; } }
1148
- CSS
1149
- @media screen {
1150
- .foo {a: b}
1151
- .bar {@extend .foo}
1152
- }
1153
- SCSS
1154
- end
1155
-
1156
- def test_extend_within_unknown_directive
1157
- assert_equal(<<CSS, render(<<SCSS))
1158
- @flooblehoof {
1159
- .foo, .bar {
1160
- a: b; } }
1161
- CSS
1162
- @flooblehoof {
1163
- .foo {a: b}
1164
- .bar {@extend .foo}
1165
- }
1166
- SCSS
1167
- end
1168
-
1169
- def test_extend_within_nested_directives
1170
- assert_equal(<<CSS, render(<<SCSS))
1171
- @media screen {
1172
- @flooblehoof {
1173
- .foo, .bar {
1174
- a: b; } } }
1175
- CSS
1176
- @media screen {
1177
- @flooblehoof {
1178
- .foo {a: b}
1179
- .bar {@extend .foo}
1180
- }
1181
- }
1182
- SCSS
1183
- end
1184
-
1185
- def test_extend_within_disparate_media
1186
- assert_equal(<<CSS, render(<<SCSS))
1187
- @media screen {
1188
- .foo, .bar {
1189
- a: b; } }
1190
- CSS
1191
- @media screen {.foo {a: b}}
1192
- @media screen {.bar {@extend .foo}}
1193
- SCSS
1194
- end
1195
-
1196
- def test_extend_within_disparate_unknown_directive
1197
- assert_equal(<<CSS, render(<<SCSS))
1198
- @flooblehoof {
1199
- .foo, .bar {
1200
- a: b; } }
1201
- @flooblehoof {}
1202
- CSS
1203
- @flooblehoof {.foo {a: b}}
1204
- @flooblehoof {.bar {@extend .foo}}
1205
- SCSS
1206
- end
1207
-
1208
- def test_extend_within_disparate_nested_directives
1209
- assert_equal(<<CSS, render(<<SCSS))
1210
- @media screen {
1211
- @flooblehoof {
1212
- .foo, .bar {
1213
- a: b; } } }
1214
- @media screen {
1215
- @flooblehoof {} }
1216
- CSS
1217
- @media screen {@flooblehoof {.foo {a: b}}}
1218
- @media screen {@flooblehoof {.bar {@extend .foo}}}
1219
- SCSS
1220
- end
1221
-
1222
- def test_extend_within_and_without_media
1223
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1224
- You may not @extend an outer selector from within @media.
1225
- You may only @extend selectors within the same directive.
1226
- From "@extend .foo" on line 4 of test_extend_within_and_without_media_inline.scss.
1227
- ERR
1228
- .foo {a: b}
1229
- @media screen {
1230
- .foo {c: d}
1231
- .bar {@extend .foo}
1232
- }
1233
- SCSS
1234
- end
1235
-
1236
- def test_extend_within_and_without_unknown_directive
1237
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1238
- You may not @extend an outer selector from within @flooblehoof.
1239
- You may only @extend selectors within the same directive.
1240
- From "@extend .foo" on line 4 of test_extend_within_and_without_unknown_directive_inline.scss.
1241
- ERR
1242
- .foo {a: b}
1243
- @flooblehoof {
1244
- .foo {c: d}
1245
- .bar {@extend .foo}
1246
- }
1247
- SCSS
1248
- end
1249
-
1250
- def test_extend_within_and_without_nested_directives
1251
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1252
- You may not @extend an outer selector from within @flooblehoof.
1253
- You may only @extend selectors within the same directive.
1254
- From "@extend .foo" on line 5 of test_extend_within_and_without_nested_directives_inline.scss.
1255
- ERR
1256
- @media screen {
1257
- .foo {a: b}
1258
- @flooblehoof {
1259
- .foo {c: d}
1260
- .bar {@extend .foo}
1261
- }
1262
- }
1263
- SCSS
1264
- end
1265
-
1266
- def test_extend_with_subject_transfers_subject_to_extender
1267
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1268
- foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
1269
- a: b; }
1270
- CSS
1271
- foo bar! baz {a: b}
1272
- .bip .bap {@extend bar}
1273
- SCSS
1274
-
1275
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1276
- foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
1277
- a: b; }
1278
- CSS
1279
- foo.x bar.y! baz.z {a: b}
1280
- .bip .bap {@extend .y}
1281
- SCSS
1282
- end
1283
-
1284
- def test_extend_with_subject_retains_subject_on_target
1285
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1286
- .foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
1287
- a: b; }
1288
- CSS
1289
- .foo! .bar {a: b}
1290
- .bip .bap {@extend .bar}
1291
- SCSS
1292
- end
1293
-
1294
- def test_extend_with_subject_transfers_subject_to_target
1295
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1296
- a.foo .bar, .bip a.bap! .bar {
1297
- a: b; }
1298
- CSS
1299
- a.foo .bar {a: b}
1300
- .bip .bap! {@extend .foo}
1301
- SCSS
1302
- end
1303
-
1304
- def test_extend_with_subject_retains_subject_on_extender
1305
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1306
- .foo .bar, .foo .bip! .bap, .bip! .foo .bap {
1307
- a: b; }
1308
- CSS
1309
- .foo .bar {a: b}
1310
- .bip! .bap {@extend .bar}
1311
- SCSS
1312
- end
1313
-
1314
- def test_extend_with_subject_fails_with_conflicting_subject
1315
- silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1316
- x! .bar {
1317
- a: b; }
1318
- CSS
1319
- x! .bar {a: b}
1320
- y! .bap {@extend .bar}
1321
- SCSS
1322
- end
1323
-
1324
- def test_extend_warns_when_extendee_doesnt_exist
1325
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1326
- ".foo" failed to @extend ".bar".
1327
- The selector ".bar" was not found.
1328
- Use "@extend .bar !optional" if the extend should be able to fail.
1329
- ERR
1330
- .foo {@extend .bar}
1331
- SCSS
1332
- end
1333
-
1334
- def test_extend_warns_when_extension_fails
1335
- assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
1336
- "b.foo" failed to @extend ".bar".
1337
- No selectors matching ".bar" could be unified with "b.foo".
1338
- Use "@extend .bar !optional" if the extend should be able to fail.
1339
- ERR
1340
- a.bar {a: b}
1341
- b.foo {@extend .bar}
1342
- SCSS
1343
- end
1344
-
1345
- def test_extend_succeeds_when_one_extension_fails_but_others_dont
1346
- assert_equal(<<CSS, render(<<SCSS))
1347
- a.bar {
1348
- a: b; }
1349
-
1350
- .bar, b.foo {
1351
- c: d; }
1352
- CSS
1353
- a.bar {a: b}
1354
- .bar {c: d}
1355
- b.foo {@extend .bar}
1356
- SCSS
1357
- end
1358
-
1359
- def test_optional_extend_succeeds_when_extendee_doesnt_exist
1360
- assert_equal("", render(<<SCSS))
1361
- .foo {@extend .bar !optional}
1362
- SCSS
1363
- end
1364
-
1365
- def test_optional_extend_succeeds_when_extension_fails
1366
- assert_equal(<<CSS, render(<<SCSS))
1367
- a.bar {
1368
- a: b; }
1369
- CSS
1370
- a.bar {a: b}
1371
- b.foo {@extend .bar !optional}
1372
- SCSS
1373
- end
1374
-
1375
- # Regression Tests
1376
-
1377
- def test_extend_with_middle_pseudo
1378
- assert_equal(<<CSS, render(<<SCSS))
1379
- .btn:active.focus, :active.focus:before {
1380
- a: b; }
1381
- CSS
1382
- .btn:active.focus {a: b}
1383
- :before {@extend .btn}
1384
- SCSS
1385
- end
1386
-
1387
- def test_extend_parent_selector_suffix
1388
- assert_equal <<CSS, render(<<SCSS)
1389
- .a-b, .c {
1390
- x: y; }
1391
- CSS
1392
- .a {&-b {x: y}}
1393
- .c {@extend .a-b}
1394
- SCSS
1395
- end
1396
-
1397
- def test_pseudo_element_superselector
1398
- # Pseudo-elements shouldn't be removed in superselector calculations.
1399
- assert_equal <<CSS, render(<<SCSS)
1400
- a#bar, a#bar::fblthp {
1401
- a: b; }
1402
- CSS
1403
- %x#bar {a: b} // Add an id to make the results have high specificity
1404
- %y, %y::fblthp {@extend %x}
1405
- a {@extend %y}
1406
- SCSS
1407
-
1408
- # Pseudo-classes can be removed when the second law allows.
1409
- assert_equal <<CSS, render(<<SCSS)
1410
- a#bar {
1411
- a: b; }
1412
- CSS
1413
- %x#bar {a: b}
1414
- %y, %y:fblthp {@extend %x}
1415
- a {@extend %y}
1416
- SCSS
1417
-
1418
- # A few pseudo-elements can be written as pseudo-elements for historical
1419
- # reasons. See http://www.w3.org/TR/selectors4/#pseudo-elements.
1420
- %w[first-line first-letter before after].each do |pseudo|
1421
- assert_equal <<CSS, render(<<SCSS)
1422
- a#bar, a#bar:#{pseudo} {
1423
- a: b; }
1424
- CSS
1425
- %x#bar {a: b}
1426
- %y, %y:#{pseudo} {@extend %x}
1427
- a {@extend %y}
1428
- SCSS
1429
- end
1430
- end
1431
-
1432
- def test_multiple_source_redundancy_elimination
1433
- assert_equal <<CSS, render(<<SCSS)
1434
- .test-case, .test-case:active {
1435
- color: red; }
1436
-
1437
- .test-case:hover {
1438
- color: green; }
1439
- CSS
1440
- %default-color {color: red}
1441
- %alt-color {color: green}
1442
-
1443
- %default-style {
1444
- @extend %default-color;
1445
- &:hover {@extend %alt-color}
1446
- &:active {@extend %default-color}
1447
- }
1448
-
1449
- .test-case {@extend %default-style}
1450
- SCSS
1451
- end
1452
-
1453
- def test_nested_sibling_extend
1454
- assert_equal <<CSS, render(<<SCSS)
1455
- .parent .bar, .parent .foo {
1456
- width: 2000px; }
1457
- CSS
1458
- .foo {@extend .bar}
1459
-
1460
- .parent {
1461
- .bar {
1462
- width: 2000px;
1463
- }
1464
- .foo {
1465
- @extend .bar
1466
- }
1467
- }
1468
- SCSS
1469
- end
1470
-
1471
- def test_parent_and_sibling_extend
1472
- assert_equal <<CSS, render(<<SCSS)
1473
- .parent1 .parent2 .child1.child2, .parent2 .parent1 .child1.child2 {
1474
- c: d; }
1475
- CSS
1476
- %foo %bar%baz {c: d}
1477
-
1478
- .parent1 {
1479
- @extend %foo;
1480
- .child1 {@extend %bar}
1481
- }
1482
-
1483
- .parent2 {
1484
- @extend %foo;
1485
- .child2 {@extend %baz}
1486
- }
1487
- SCSS
1488
- end
1489
-
1490
- def test_nested_extend_specificity
1491
- assert_equal <<CSS, render(<<SCSS)
1492
- a :b, a :b:c {
1493
- a: b; }
1494
- CSS
1495
- %foo {a: b}
1496
-
1497
- a {
1498
- :b {@extend %foo}
1499
- :b:c {@extend %foo}
1500
- }
1501
- SCSS
1502
- end
1503
-
1504
- def test_nested_double_extend_optimization
1505
- assert_equal <<CSS, render(<<SCSS)
1506
- .parent1 .child {
1507
- a: b; }
1508
- CSS
1509
- %foo %bar {
1510
- a: b;
1511
- }
1512
-
1513
- .parent1 {
1514
- @extend %foo;
1515
-
1516
- .child {
1517
- @extend %bar;
1518
- }
1519
- }
1520
-
1521
- .parent2 {
1522
- @extend %foo;
1523
- }
1524
- SCSS
1525
- end
1526
-
1527
- def test_extend_in_double_nested_media_query
1528
- assert_equal <<CSS, render(<<SCSS)
1529
- @media all and (orientation: landscape) {
1530
- .bar {
1531
- color: blue; } }
1532
- CSS
1533
- @media all {
1534
- @media (orientation: landscape) {
1535
- %foo {color: blue}
1536
- .bar {@extend %foo}
1537
- }
1538
- }
1539
- SCSS
1540
- end
1541
-
1542
- def test_partially_failed_extend
1543
- assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1544
- .rc, test {
1545
- color: white; }
1546
-
1547
- .prices span.pill span.rc {
1548
- color: red; }
1549
- CSS
1550
- test { @extend .rc; }
1551
- .rc {color: white;}
1552
- .prices span.pill span.rc {color: red;}
1553
- SCSS
1554
- end
1555
-
1556
- def test_newline_near_combinator
1557
- assert_equal <<CSS, render(<<SCSS)
1558
- .a +
1559
- .b x, .a +
1560
- .b .c y, .c .a +
1561
- .b y {
1562
- a: b; }
1563
- CSS
1564
- .a +
1565
- .b x {a: b}
1566
- .c y {@extend x}
1567
- SCSS
1568
- end
1569
-
1570
- def test_duplicated_selector_with_newlines
1571
- assert_equal(<<CSS, render(<<SCSS))
1572
- .example-1-1,
1573
- .example-1-2,
1574
- .my-page-1 .my-module-1-1,
1575
- .example-1-3 {
1576
- a: b; }
1577
- CSS
1578
- .example-1-1,
1579
- .example-1-2,
1580
- .example-1-3 {
1581
- a: b;
1582
- }
1583
-
1584
- .my-page-1 .my-module-1-1 {@extend .example-1-2}
1585
- SCSS
1586
- end
1587
-
1588
- def test_nested_selector_with_child_selector_hack_extendee
1589
- assert_extends '> .foo', 'foo bar {@extend .foo}', '> .foo, > foo bar'
1590
- end
1591
-
1592
- def test_nested_selector_with_child_selector_hack_extender
1593
- assert_extends '.foo .bar', '> foo bar {@extend .bar}', '.foo .bar, > .foo foo bar, > foo .foo bar'
1594
- end
1595
-
1596
- def test_nested_selector_with_child_selector_hack_extender_and_extendee
1597
- assert_extends '> .foo', '> foo bar {@extend .foo}', '> .foo, > foo bar'
1598
- end
1599
-
1600
- def test_nested_selector_with_child_selector_hack_extender_and_sibling_selector_extendee
1601
- assert_extends '~ .foo', '> foo bar {@extend .foo}', '~ .foo'
1602
- end
1603
-
1604
- def test_nested_selector_with_child_selector_hack_extender_and_extendee_and_newline
1605
- assert_equal <<CSS, render(<<SCSS)
1606
- > .foo, > flip,
1607
- > foo bar {
1608
- a: b; }
1609
- CSS
1610
- > .foo {a: b}
1611
- flip,
1612
- > foo bar {@extend .foo}
1613
- SCSS
1614
- end
1615
-
1616
- def test_extended_parent_and_child_redundancy_elimination
1617
- assert_equal <<CSS, render(<<SCSS)
1618
- a b, d b, a c, d c {
1619
- a: b; }
1620
- CSS
1621
- a {
1622
- b {a: b}
1623
- c {@extend b}
1624
- }
1625
- d {@extend a}
1626
- SCSS
1627
- end
1628
-
1629
- def test_extend_redundancy_elimination_when_it_would_reduce_specificity
1630
- assert_extends 'a', 'a.foo {@extend a}', 'a, a.foo'
1631
- end
1632
-
1633
- def test_extend_redundancy_elimination_when_it_would_preserve_specificity
1634
- assert_extends '.bar a', 'a.foo {@extend a}', '.bar a'
1635
- end
1636
-
1637
- def test_extend_redundancy_elimination_never_eliminates_base_selector
1638
- assert_extends 'a.foo', '.foo {@extend a}', 'a.foo, .foo'
1639
- end
1640
-
1641
- def test_extend_cross_branch_redundancy_elimination
1642
- assert_equal <<CSS, render(<<SCSS)
1643
- .a .c .d, .b .c .a .d {
1644
- a: b; }
1645
- CSS
1646
- %x .c %y {a: b}
1647
- .a, .b {@extend %x}
1648
- .a .d {@extend %y}
1649
- SCSS
1650
-
1651
- assert_equal <<CSS, render(<<SCSS)
1652
- .e .a .c .d, .a .c .e .d, .e .b .c .a .d, .b .c .a .e .d {
1653
- a: b; }
1654
- CSS
1655
- .e %z {a: b}
1656
- %x .c %y {@extend %z}
1657
- .a, .b {@extend %x}
1658
- .a .d {@extend %y}
1659
- SCSS
1660
- end
1661
-
1662
- private
1663
-
1664
- def assert_extend_doesnt_match(extender, target, reason, line, syntax = :scss)
1665
- message = "\"#{extender}\" failed to @extend \"#{target}\"."
1666
- reason =
1667
- if reason == :not_found
1668
- "The selector \"#{target}\" was not found."
1669
- else
1670
- "No selectors matching \"#{target}\" could be unified with \"#{extender}\"."
1671
- end
1672
-
1673
- assert_raise_message(Sass::SyntaxError, <<ERR) {yield}
1674
- #{message}
1675
- #{reason}
1676
- Use "@extend #{target} !optional" if the extend should be able to fail.
1677
- ERR
1678
- end
1679
-
1680
- def assert_unification(selector, extension, unified, nested = true)
1681
- # Do some trickery so the first law of extend doesn't get in our way.
1682
- assert_extends(
1683
- "%-a #{selector}",
1684
- extension + " -a {@extend %-a}",
1685
- unified.split(', ').map {|s| "-a #{s}"}.join(', '))
1686
- end
1687
-
1688
- def assert_specificity_equals(sel1, sel2)
1689
- assert_specificity_gte(sel1, sel2)
1690
- assert_specificity_gte(sel2, sel1)
1691
- end
1692
-
1693
- def assert_specificity_gte(sel1, sel2)
1694
- assert_equal <<CSS, render(<<SCSS)
1695
- #{sel1} .a {
1696
- a: b; }
1697
- CSS
1698
- #{sel1} %-a {a: b}
1699
- .a {@extend %-a}
1700
- #{sel2}.a {@extend %-a}
1701
- SCSS
1702
- end
1703
-
1704
- def render_unification(selector, extension)
1705
- render_extends(
1706
- "%-a #{selector}",
1707
- extension + " -a {@extend %-a}")
1708
- end
1709
-
1710
- def assert_extends(selector, extension, result)
1711
- assert_equal <<CSS, render_extends(selector, extension)
1712
- #{result} {
1713
- a: b; }
1714
- CSS
1715
- end
1716
-
1717
- def assert_extends_to_nothing(selector, extension)
1718
- assert_equal '', render_extends(selector, extension)
1719
- end
1720
-
1721
- def render_extends(selector, extension)
1722
- render(<<SCSS)
1723
- #{selector} {a: b}
1724
- #{extension}
1725
- SCSS
1726
- end
1727
-
1728
- def render(sass, options = {})
1729
- options = {:syntax => :scss}.merge(options)
1730
- munge_filename options
1731
- Sass::Engine.new(sass, options).render
1732
- end
1733
- end