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