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
data/lib/sass/scss.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'sass/scss/rx'
|
2
|
+
require 'sass/scss/script_lexer'
|
3
|
+
require 'sass/scss/script_parser'
|
4
|
+
require 'sass/scss/parser'
|
5
|
+
require 'sass/scss/static_parser'
|
6
|
+
require 'sass/scss/css_parser'
|
7
|
+
|
8
|
+
module Sass
|
9
|
+
# SCSS is the CSS syntax for Sass.
|
10
|
+
# It parses into the same syntax tree as Sass,
|
11
|
+
# and generates the same sort of output CSS.
|
12
|
+
#
|
13
|
+
# This module contains code for the parsing of SCSS.
|
14
|
+
# The evaluation is handled by the broader {Sass} module.
|
15
|
+
module SCSS; end
|
16
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Sass
|
2
|
+
module Selector
|
3
|
+
# The abstract parent class of the various selector sequence classes.
|
4
|
+
#
|
5
|
+
# All subclasses should implement a `members` method that returns an array
|
6
|
+
# of object that respond to `#line=` and `#filename=`, as well as a `to_s`
|
7
|
+
# method that returns the string representation of the selector.
|
8
|
+
class AbstractSequence
|
9
|
+
# The line of the Sass template on which this selector was declared.
|
10
|
+
#
|
11
|
+
# @return [Fixnum]
|
12
|
+
attr_reader :line
|
13
|
+
|
14
|
+
# The name of the file in which this selector was declared.
|
15
|
+
#
|
16
|
+
# @return [String, nil]
|
17
|
+
attr_reader :filename
|
18
|
+
|
19
|
+
# Sets the line of the Sass template on which this selector was declared.
|
20
|
+
# This also sets the line for all child selectors.
|
21
|
+
#
|
22
|
+
# @param line [Fixnum]
|
23
|
+
# @return [Fixnum]
|
24
|
+
def line=(line)
|
25
|
+
members.each {|m| m.line = line}
|
26
|
+
@line = line
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the name of the file in which this selector was declared,
|
30
|
+
# or `nil` if it was not declared in a file (e.g. on stdin).
|
31
|
+
# This also sets the filename for all child selectors.
|
32
|
+
#
|
33
|
+
# @param filename [String, nil]
|
34
|
+
# @return [String, nil]
|
35
|
+
def filename=(filename)
|
36
|
+
members.each {|m| m.filename = filename}
|
37
|
+
@filename = filename
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a hash code for this sequence.
|
41
|
+
#
|
42
|
+
# Subclasses should define `#_hash` rather than overriding this method,
|
43
|
+
# which automatically handles memoizing the result.
|
44
|
+
#
|
45
|
+
# @return [Fixnum]
|
46
|
+
def hash
|
47
|
+
@_hash ||= _hash
|
48
|
+
end
|
49
|
+
|
50
|
+
# Checks equality between this and another object.
|
51
|
+
#
|
52
|
+
# Subclasses should define `#_eql?` rather than overriding this method,
|
53
|
+
# which handles checking class equality and hash equality.
|
54
|
+
#
|
55
|
+
# @param other [Object] The object to test equality against
|
56
|
+
# @return [Boolean] Whether or not this is equal to `other`
|
57
|
+
def eql?(other)
|
58
|
+
other.class == self.class && other.hash == hash && _eql?(other)
|
59
|
+
end
|
60
|
+
alias_method :==, :eql?
|
61
|
+
|
62
|
+
# Whether or not this selector sequence contains a placeholder selector.
|
63
|
+
# Checks recursively.
|
64
|
+
def has_placeholder?
|
65
|
+
@has_placeholder ||= members.any? do |m|
|
66
|
+
next m.has_placeholder? if m.is_a?(AbstractSequence)
|
67
|
+
next m.selector && m.selector.has_placeholder? if m.is_a?(Pseudo)
|
68
|
+
m.is_a?(Placeholder)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the selector string.
|
73
|
+
#
|
74
|
+
# @return [String]
|
75
|
+
def to_s
|
76
|
+
Sass::Util.abstract(self)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the specificity of the selector.
|
80
|
+
#
|
81
|
+
# The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
|
82
|
+
# number or a range representing possible specificities.
|
83
|
+
#
|
84
|
+
# @return [Fixnum, Range]
|
85
|
+
def specificity
|
86
|
+
_specificity(members)
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def _specificity(arr)
|
92
|
+
min = 0
|
93
|
+
max = 0
|
94
|
+
arr.each do |m|
|
95
|
+
next if m.is_a?(String)
|
96
|
+
spec = m.specificity
|
97
|
+
if spec.is_a?(Range)
|
98
|
+
min += spec.begin
|
99
|
+
max += spec.end
|
100
|
+
else
|
101
|
+
min += spec
|
102
|
+
max += spec
|
103
|
+
end
|
104
|
+
end
|
105
|
+
min == max ? min : (min..max)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module Sass
|
2
|
+
module Selector
|
3
|
+
# A comma-separated sequence of selectors.
|
4
|
+
class CommaSequence < AbstractSequence
|
5
|
+
# The comma-separated selector sequences
|
6
|
+
# represented by this class.
|
7
|
+
#
|
8
|
+
# @return [Array<Sequence>]
|
9
|
+
attr_reader :members
|
10
|
+
|
11
|
+
# @param seqs [Array<Sequence>] See \{#members}
|
12
|
+
def initialize(seqs)
|
13
|
+
@members = seqs
|
14
|
+
end
|
15
|
+
|
16
|
+
# Resolves the {Parent} selectors within this selector
|
17
|
+
# by replacing them with the given parent selector,
|
18
|
+
# handling commas appropriately.
|
19
|
+
#
|
20
|
+
# @param super_cseq [CommaSequence] The parent selector
|
21
|
+
# @param implicit_parent [Boolean] Whether the the parent
|
22
|
+
# selector should automatically be prepended to the resolved
|
23
|
+
# selector if it contains no parent refs.
|
24
|
+
# @return [CommaSequence] This selector, with parent references resolved
|
25
|
+
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
26
|
+
def resolve_parent_refs(super_cseq, implicit_parent = true)
|
27
|
+
if super_cseq.nil?
|
28
|
+
if @members.any? do |sel|
|
29
|
+
sel.members.any? do |sel_or_op|
|
30
|
+
sel_or_op.is_a?(SimpleSequence) &&
|
31
|
+
sel_or_op.members.any? {|ssel| ssel.is_a?(Parent)}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
raise Sass::SyntaxError.new(
|
35
|
+
"Base-level rules cannot contain the parent-selector-referencing character '&'.")
|
36
|
+
end
|
37
|
+
return self
|
38
|
+
end
|
39
|
+
|
40
|
+
CommaSequence.new(Sass::Util.flatten_vertically(@members.map do |seq|
|
41
|
+
seq.resolve_parent_refs(super_cseq, implicit_parent).members
|
42
|
+
end))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Non-destrucively extends this selector with the extensions specified in a hash
|
46
|
+
# (which should come from {Sass::Tree::Visitors::Cssize}).
|
47
|
+
#
|
48
|
+
# @todo Link this to the reference documentation on `@extend`
|
49
|
+
# when such a thing exists.
|
50
|
+
#
|
51
|
+
# @param extends [Sass::Util::SubsetMap{Selector::Simple =>
|
52
|
+
# Sass::Tree::Visitors::Cssize::Extend}]
|
53
|
+
# The extensions to perform on this selector
|
54
|
+
# @param parent_directives [Array<Sass::Tree::DirectiveNode>]
|
55
|
+
# The directives containing this selector.
|
56
|
+
# @param replace [Boolean]
|
57
|
+
# Whether to replace the original selector entirely or include
|
58
|
+
# it in the result.
|
59
|
+
# @param seen [Set<Array<Selector::Simple>>]
|
60
|
+
# The set of simple sequences that are currently being replaced.
|
61
|
+
# @param original [Boolean]
|
62
|
+
# Whether this is the original selector being extended, as opposed to
|
63
|
+
# the result of a previous extension that's being re-extended.
|
64
|
+
# @return [CommaSequence] A copy of this selector,
|
65
|
+
# with extensions made according to `extends`
|
66
|
+
def do_extend(extends, parent_directives = [], replace = false, seen = Set.new,
|
67
|
+
original = true)
|
68
|
+
CommaSequence.new(members.map do |seq|
|
69
|
+
seq.do_extend(extends, parent_directives, replace, seen, original)
|
70
|
+
end.flatten)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns whether or not this selector matches all elements
|
74
|
+
# that the given selector matches (as well as possibly more).
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# (.foo).superselector?(.foo.bar) #=> true
|
78
|
+
# (.foo).superselector?(.bar) #=> false
|
79
|
+
# @param cseq [CommaSequence]
|
80
|
+
# @return [Boolean]
|
81
|
+
def superselector?(cseq)
|
82
|
+
cseq.members.all? {|seq1| members.any? {|seq2| seq2.superselector?(seq1)}}
|
83
|
+
end
|
84
|
+
|
85
|
+
# Populates a subset map that can then be used to extend
|
86
|
+
# selectors. This registers an extension with this selector as
|
87
|
+
# the extender and `extendee` as the extendee.
|
88
|
+
#
|
89
|
+
# @param extends [Sass::Util::SubsetMap{Selector::Simple =>
|
90
|
+
# Sass::Tree::Visitors::Cssize::Extend}]
|
91
|
+
# The subset map representing the extensions to perform.
|
92
|
+
# @param extendee [CommaSequence] The selector being extended.
|
93
|
+
# @param extend_node [Sass::Tree::ExtendNode]
|
94
|
+
# The node that caused this extension.
|
95
|
+
# @param parent_directives [Array<Sass::Tree::DirectiveNode>]
|
96
|
+
# The parent directives containing `extend_node`.
|
97
|
+
# @raise [Sass::SyntaxError] if this extension is invalid.
|
98
|
+
def populate_extends(extends, extendee, extend_node = nil, parent_directives = [])
|
99
|
+
extendee.members.each do |seq|
|
100
|
+
if seq.members.size > 1
|
101
|
+
raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
|
102
|
+
end
|
103
|
+
|
104
|
+
sseq = seq.members.first
|
105
|
+
if !sseq.is_a?(Sass::Selector::SimpleSequence)
|
106
|
+
raise Sass::SyntaxError.new("Can't extend #{seq}: invalid selector")
|
107
|
+
elsif sseq.members.any? {|ss| ss.is_a?(Sass::Selector::Parent)}
|
108
|
+
raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend parent selectors")
|
109
|
+
end
|
110
|
+
|
111
|
+
sel = sseq.members
|
112
|
+
members.each do |member|
|
113
|
+
unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
|
114
|
+
raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
|
115
|
+
end
|
116
|
+
|
117
|
+
extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
|
118
|
+
member, sel, extend_node, parent_directives, :not_found)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Unifies this with another comma selector to produce a selector
|
124
|
+
# that matches (a subset of) the intersection of the two inputs.
|
125
|
+
#
|
126
|
+
# @param other [CommaSequence]
|
127
|
+
# @return [CommaSequence, nil] The unified selector, or nil if unification failed.
|
128
|
+
# @raise [Sass::SyntaxError] If this selector cannot be unified.
|
129
|
+
# This will only ever occur when a dynamic selector,
|
130
|
+
# such as {Parent} or {Interpolation}, is used in unification.
|
131
|
+
# Since these selectors should be resolved
|
132
|
+
# by the time extension and unification happen,
|
133
|
+
# this exception will only ever be raised as a result of programmer error
|
134
|
+
def unify(other)
|
135
|
+
results = members.map {|seq1| other.members.map {|seq2| seq1.unify(seq2)}}.flatten.compact
|
136
|
+
results.empty? ? nil : CommaSequence.new(results.map {|cseq| cseq.members}.flatten)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns a SassScript representation of this selector.
|
140
|
+
#
|
141
|
+
# @return [Sass::Script::Value::List]
|
142
|
+
def to_sass_script
|
143
|
+
Sass::Script::Value::List.new(members.map do |seq|
|
144
|
+
Sass::Script::Value::List.new(seq.members.map do |component|
|
145
|
+
next if component == "\n"
|
146
|
+
Sass::Script::Value::String.new(component.to_s)
|
147
|
+
end.compact, :space)
|
148
|
+
end, :comma)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Returns a string representation of the sequence.
|
152
|
+
# This is basically the selector string.
|
153
|
+
#
|
154
|
+
# @return [String]
|
155
|
+
def inspect
|
156
|
+
members.map {|m| m.inspect}.join(", ")
|
157
|
+
end
|
158
|
+
|
159
|
+
# @see AbstractSequence#to_s
|
160
|
+
def to_s
|
161
|
+
@members.join(", ").gsub(", \n", ",\n")
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def _hash
|
167
|
+
members.hash
|
168
|
+
end
|
169
|
+
|
170
|
+
def _eql?(other)
|
171
|
+
other.class == self.class && other.members.eql?(members)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
module Sass
|
2
|
+
module Selector
|
3
|
+
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
|
4
|
+
# selector. It can have arguments (e.g. `:nth-child(2n+1)`) which can
|
5
|
+
# contain selectors (e.g. `:nth-child(2n+1 of .foo)`).
|
6
|
+
class Pseudo < Simple
|
7
|
+
# Some pseudo-class-syntax selectors are actually considered
|
8
|
+
# pseudo-elements and must be treated differently. This is a list of such
|
9
|
+
# selectors.
|
10
|
+
#
|
11
|
+
# @return [Set<String>]
|
12
|
+
ACTUALLY_ELEMENTS = %w[after before first-line first-letter].to_set
|
13
|
+
|
14
|
+
# Like \{#type}, but returns the type of selector this looks like, rather
|
15
|
+
# than the type it is semantically. This only differs from type for
|
16
|
+
# selectors in \{ACTUALLY\_ELEMENTS}.
|
17
|
+
#
|
18
|
+
# @return [Symbol]
|
19
|
+
attr_reader :syntactic_type
|
20
|
+
|
21
|
+
# The name of the selector.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
# The argument to the selector,
|
27
|
+
# or `nil` if no argument was given.
|
28
|
+
#
|
29
|
+
# @return [String, nil]
|
30
|
+
attr_reader :arg
|
31
|
+
|
32
|
+
# The selector argument, or `nil` if no selector exists.
|
33
|
+
#
|
34
|
+
# If this and \{#arg\} are both set, \{#arg\} is considered a non-selector
|
35
|
+
# prefix.
|
36
|
+
#
|
37
|
+
# @return [CommaSequence]
|
38
|
+
attr_reader :selector
|
39
|
+
|
40
|
+
# @param syntactic_type [Symbol] See \{#syntactic_type}
|
41
|
+
# @param name [String] See \{#name}
|
42
|
+
# @param arg [nil, String] See \{#arg}
|
43
|
+
# @param selector [nil, CommaSequence] See \{#selector}
|
44
|
+
def initialize(syntactic_type, name, arg, selector)
|
45
|
+
@syntactic_type = syntactic_type
|
46
|
+
@name = name
|
47
|
+
@arg = arg
|
48
|
+
@selector = selector
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns a copy of this with \{#selector} set to \{#new\_selector}.
|
52
|
+
#
|
53
|
+
# @param new_selector [CommaSequence]
|
54
|
+
# @return [CommaSequence]
|
55
|
+
def with_selector(new_selector)
|
56
|
+
Pseudo.new(syntactic_type, name, arg, CommaSequence.new(new_selector.members.map do |seq|
|
57
|
+
next seq unless seq.members.length == 1
|
58
|
+
sseq = seq.members.first
|
59
|
+
next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
|
60
|
+
sel = sseq.members.first
|
61
|
+
next seq unless sel.is_a?(Pseudo) && sel.selector
|
62
|
+
|
63
|
+
case normalized_name
|
64
|
+
when 'not'
|
65
|
+
# In theory, if there's a nested :not its contents should be
|
66
|
+
# unified with the return value. For example, if :not(.foo)
|
67
|
+
# extends .bar, :not(.bar) should become .foo:not(.bar). However,
|
68
|
+
# this is a narrow edge case and supporting it properly would make
|
69
|
+
# this code and the code calling it a lot more complicated, so
|
70
|
+
# it's not supported for now.
|
71
|
+
next [] unless sel.normalized_name == 'matches'
|
72
|
+
sel.selector.members
|
73
|
+
when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
|
74
|
+
# As above, we could theoretically support :not within :matches, but
|
75
|
+
# doing so would require this method and its callers to handle much
|
76
|
+
# more complex cases that likely aren't worth the pain.
|
77
|
+
next [] unless sel.name == name && sel.arg == arg
|
78
|
+
sel.selector.members
|
79
|
+
when 'has', 'host', 'host-context'
|
80
|
+
# We can't expand nested selectors here, because each layer adds an
|
81
|
+
# additional layer of semantics. For example, `:has(:has(img))`
|
82
|
+
# doesn't match `<div><img></div>` but `:has(img)` does.
|
83
|
+
sel
|
84
|
+
else
|
85
|
+
[]
|
86
|
+
end
|
87
|
+
end.flatten))
|
88
|
+
end
|
89
|
+
|
90
|
+
# The type of the selector. `:class` if this is a pseudoclass selector,
|
91
|
+
# `:element` if it's a pseudoelement.
|
92
|
+
#
|
93
|
+
# @return [Symbol]
|
94
|
+
def type
|
95
|
+
ACTUALLY_ELEMENTS.include?(normalized_name) ? :element : syntactic_type
|
96
|
+
end
|
97
|
+
|
98
|
+
# Like \{#name\}, but without any vendor prefix.
|
99
|
+
#
|
100
|
+
# @return [String]
|
101
|
+
def normalized_name
|
102
|
+
@normalized_name ||= name.gsub(/^-[a-zA-Z0-9]+-/, '')
|
103
|
+
end
|
104
|
+
|
105
|
+
# @see Selector#to_s
|
106
|
+
def to_s
|
107
|
+
res = (syntactic_type == :class ? ":" : "::") + @name
|
108
|
+
if @arg || @selector
|
109
|
+
res << "("
|
110
|
+
res << @arg.strip if @arg
|
111
|
+
res << " " if @arg && @selector
|
112
|
+
res << @selector.to_s if @selector
|
113
|
+
res << ")"
|
114
|
+
end
|
115
|
+
res
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns `nil` if this is a pseudoelement selector
|
119
|
+
# and `sels` contains a pseudoelement selector different than this one.
|
120
|
+
#
|
121
|
+
# @see SimpleSequence#unify
|
122
|
+
def unify(sels)
|
123
|
+
return if type == :element && sels.any? do |sel|
|
124
|
+
sel.is_a?(Pseudo) && sel.type == :element &&
|
125
|
+
(sel.name != name || sel.arg != arg || sel.selector != selector)
|
126
|
+
end
|
127
|
+
super
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns whether or not this selector matches all elements
|
131
|
+
# that the given selector matches (as well as possibly more).
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# (.foo).superselector?(.foo.bar) #=> true
|
135
|
+
# (.foo).superselector?(.bar) #=> false
|
136
|
+
# @param their_sseq [SimpleSequence]
|
137
|
+
# @param parents [Array<SimpleSequence, String>] The parent selectors of `their_sseq`, if any.
|
138
|
+
# @return [Boolean]
|
139
|
+
def superselector?(their_sseq, parents = [])
|
140
|
+
case normalized_name
|
141
|
+
when 'matches', 'any'
|
142
|
+
# :matches can be a superselector of another selector in one of two
|
143
|
+
# ways. Either its constituent selectors can be a superset of those of
|
144
|
+
# another :matches in the other selector, or any of its constituent
|
145
|
+
# selectors can individually be a superselector of the other selector.
|
146
|
+
(their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
|
147
|
+
next false unless their_sel.is_a?(Pseudo)
|
148
|
+
next false unless their_sel.name == name
|
149
|
+
selector.superselector?(their_sel.selector)
|
150
|
+
end || selector.members.any? do |our_seq|
|
151
|
+
their_seq = Sequence.new(parents + [their_sseq])
|
152
|
+
our_seq.superselector?(their_seq)
|
153
|
+
end
|
154
|
+
when 'has', 'host', 'host-context'
|
155
|
+
# Like :matches, :has (et al) can be a superselector of another
|
156
|
+
# selector if its constituent selectors are a superset of those of
|
157
|
+
# another :has in the other selector. However, the :matches other case
|
158
|
+
# doesn't work, because :has refers to nested elements.
|
159
|
+
(their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
|
160
|
+
next false unless their_sel.is_a?(Pseudo)
|
161
|
+
next false unless their_sel.name == name
|
162
|
+
selector.superselector?(their_sel.selector)
|
163
|
+
end
|
164
|
+
when 'not'
|
165
|
+
selector.members.all? do |our_seq|
|
166
|
+
their_sseq.members.any? do |their_sel|
|
167
|
+
if their_sel.is_a?(Element) || their_sel.is_a?(Id)
|
168
|
+
# `:not(a)` is a superselector of `h1` and `:not(#foo)` is a
|
169
|
+
# superselector of `#bar`.
|
170
|
+
our_sseq = our_seq.members.last
|
171
|
+
next false unless our_sseq.is_a?(SimpleSequence)
|
172
|
+
our_sseq.members.any? do |our_sel|
|
173
|
+
our_sel.class == their_sel.class && our_sel != their_sel
|
174
|
+
end
|
175
|
+
else
|
176
|
+
next false unless their_sel.is_a?(Pseudo)
|
177
|
+
next false unless their_sel.name == name
|
178
|
+
# :not(X) is a superselector of :not(Y) exactly when Y is a
|
179
|
+
# superselector of X.
|
180
|
+
their_sel.selector.superselector?(CommaSequence.new([our_seq]))
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
when 'current'
|
185
|
+
(their_sseq.selector_pseudo_classes['current'] || []).any? do |their_current|
|
186
|
+
next false if their_current.name != name
|
187
|
+
# Explicitly don't check for nested superselector relationships
|
188
|
+
# here. :current(.foo) isn't always a superselector of
|
189
|
+
# :current(.foo.bar), since it matches the *innermost* ancestor of
|
190
|
+
# the current element that matches the selector. For example:
|
191
|
+
#
|
192
|
+
# <div class="foo bar">
|
193
|
+
# <p class="foo">
|
194
|
+
# <span>current element</span>
|
195
|
+
# </p>
|
196
|
+
# </div>
|
197
|
+
#
|
198
|
+
# Here :current(.foo) would match the p element and *not* the div
|
199
|
+
# element, whereas :current(.foo.bar) would match the div and not
|
200
|
+
# the p.
|
201
|
+
selector == their_current.selector
|
202
|
+
end
|
203
|
+
when 'nth-child', 'nth-last-child'
|
204
|
+
their_sseq.members.any? do |their_sel|
|
205
|
+
# This misses a few edge cases. For example, `:nth-child(n of X)`
|
206
|
+
# is a superselector of `X`, and `:nth-child(2n of X)` is a
|
207
|
+
# superselector of `:nth-child(4n of X)`. These seem rare enough
|
208
|
+
# not to be worth worrying about, though.
|
209
|
+
next false unless their_sel.is_a?(Pseudo)
|
210
|
+
next false unless their_sel.name == name
|
211
|
+
next false unless their_sel.arg == arg
|
212
|
+
selector.superselector?(their_sel.selector)
|
213
|
+
end
|
214
|
+
else
|
215
|
+
throw "[BUG] Unknown selector pseudo class #{name}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# @see AbstractSequence#specificity
|
220
|
+
def specificity
|
221
|
+
return 1 if type == :element
|
222
|
+
return SPECIFICITY_BASE unless selector
|
223
|
+
@specificity ||=
|
224
|
+
if normalized_name == 'not'
|
225
|
+
min = 0
|
226
|
+
max = 0
|
227
|
+
selector.members.each do |seq|
|
228
|
+
spec = seq.specificity
|
229
|
+
if spec.is_a?(Range)
|
230
|
+
min = Sass::Util.max(spec.begin, min)
|
231
|
+
max = Sass::Util.max(spec.end, max)
|
232
|
+
else
|
233
|
+
min = Sass::Util.max(spec, min)
|
234
|
+
max = Sass::Util.max(spec, max)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
min == max ? max : (min..max)
|
238
|
+
else
|
239
|
+
min = 0
|
240
|
+
max = 0
|
241
|
+
selector.members.each do |seq|
|
242
|
+
spec = seq.specificity
|
243
|
+
if spec.is_a?(Range)
|
244
|
+
min = Sass::Util.min(spec.begin, min)
|
245
|
+
max = Sass::Util.max(spec.end, max)
|
246
|
+
else
|
247
|
+
min = Sass::Util.min(spec, min)
|
248
|
+
max = Sass::Util.max(spec, max)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
min == max ? max : (min..max)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|