moduleSassmoduleSelector# An operator-separated sequence of# {SimpleSequence simple selector sequences}.classSequence<AbstractSequence# Sets the line of the Sass template on which this selector was declared.# This also sets the line for all child selectors.## @param line [Fixnum]# @return [Fixnum]defline=(line)members.each{|m|m.line=lineifm.is_a?(SimpleSequence)}lineend# Sets the name of the file in which this selector was declared,# or `nil` if it was not declared in a file (e.g. on stdin).# This also sets the filename for all child selectors.## @param filename [String, nil]# @return [String, nil]deffilename=(filename)members.each{|m|m.filename=filenameifm.is_a?(SimpleSequence)}filenameend# The array of {SimpleSequence simple selector sequences}, operators, and newlines.# The operators are strings such as `"+"` and `">"`# representing the corresponding CSS operators.# Newlines are also newline strings;# these aren't semantically relevant,# but they do affect formatting.## @return [Array<SimpleSequence, String>]attr_reader:members# @param seqs_and_ops [Array<SimpleSequence, String>] See \{#members}definitialize(seqs_and_ops)@members=seqs_and_opsend# Resolves the {Parent} selectors within this selector# by replacing them with the given parent selector,# handling commas appropriately.## @param super_seq [Sequence] The parent selector sequence# @return [Sequence] This selector, with parent references resolved# @raise [Sass::SyntaxError] If a parent selector is invaliddefresolve_parent_refs(super_seq)members=@membersnl=(members.first=="\n"&&members.shift)unlessmembers.any?do|seq_or_op|seq_or_op.is_a?(SimpleSequence)&&seq_or_op.members.first.is_a?(Parent)endmembers=[]members<<nlifnlmembers<<SimpleSequence.new([Parent.new])members+=@membersendSequence.new(members.mapdo|seq_or_op|nextseq_or_opunlessseq_or_op.is_a?(SimpleSequence)seq_or_op.resolve_parent_refs(super_seq)end.flatten)end# Non-destructively extends this selector with the extensions specified in a hash# (which should come from {Sass::Tree::Visitors::Cssize}).## @overload def do_extend(extends)# @param extends [Sass::Util::SubsetMap{Selector::Simple => Selector::Sequence}]# The extensions to perform on this selector# @return [Array<Sequence>] A list of selectors generated# by extending this selector with `extends`.# These correspond to a {CommaSequence}'s {CommaSequence#members members array}.# @see CommaSequence#do_extenddefdo_extend(extends,seen=Set.new)paths=Sass::Util.paths(members.mapdo|sseq_or_op|next[[sseq_or_op]]unlesssseq_or_op.is_a?(SimpleSequence)extended=sseq_or_op.do_extend(extends,seen)choices=extended.map{|seq|seq.members}choices.unshift([sseq_or_op])unlessextended.any?{|seq|seq.superselector?(sseq_or_op)}choicesend)Sass::Util.flatten(paths.map{|path|weave(path)},1).map{|p|Sequence.new(p)}end# Returns whether or not this selector matches all elements# that the given selector matches (as well as possibly more).## @example# (.foo).superselector?(.foo.bar) #=> true# (.foo).superselector?(.bar) #=> false# (.bar .foo).superselector?(.foo) #=> false# @param sseq [SimpleSequence]# @return [Boolean]defsuperselector?(sseq)returnfalseunlessmembers.size==1members.last.superselector?(sseq)end# @see Simple#to_adefto_aary=@members.map{|seq_or_op|seq_or_op.is_a?(SimpleSequence)?seq_or_op.to_a:seq_or_op}Sass::Util.intersperse(ary," ").flatten.compactend# Returns a string representation of the sequence.# This is basically the selector string.## @return [String]definspectmembers.map{|m|m.inspect}.join(" ")endprivate# Conceptually, this expands "parenthesized selectors".# That is, if we have `.A .B {@extend .C}` and `.D .C {...}`,# this conceptually expands into `.D .C, .D (.A .B)`,# and this function translates `.D (.A .B)` into `.D .A .B, .A.D .B, .D .A .B`.## @param path [Array<Array<SimpleSequence or String>>] A list of parenthesized selector groups.# @return [Array<Array<SimpleSequence or String>>] A list of fully-expanded selectors.defweave(path)befores=[[]]afters=path.dupuntilafters.empty?current=afters.shift.duplast_current=[current.pop]while!current.empty?&&last_current.first.is_a?(String)||current.last.is_a?(String)last_current.unshift(current.pop)endbefores=Sass::Util.flatten(befores.mapdo|before|subweave(before,current).map{|seqs|seqs+last_current}end,1)returnbeforesifafters.empty?endend# This interweaves two lists of selectors,# returning all possible orderings of them (including using unification)# that maintain the relative ordering of the input arrays.## For example, given `.foo .bar` and `.baz .bang`,# this would return `.foo .bar .baz .bang`, `.foo .bar.baz .bang`,# `.foo .baz .bar .bang`, `.foo .baz .bar.bang`, `.foo .baz .bang .bar`,# and so on until `.baz .bang .foo .bar`.## @overload def subweave(seq1, seq2)# @param seq1 [Array<SimpleSequence or String>]# @param seq2 [Array<SimpleSequence or String>]# @return [Array<Array<SimpleSequence or String>>]defsubweave(seq1,seq2,cache={})return[seq2]ifseq1.empty?return[seq1]ifseq2.empty?seq1=group_selectors(seq1)seq2=group_selectors(seq2)lcs=Sass::Util.lcs(seq2,seq1)do|s1,s2|nexts1ifs1==s2nextunlesss1.first.is_a?(SimpleSequence)&&s2.first.is_a?(SimpleSequence)nexts2ifsubweave_superselector?(s1,s2)nexts1ifsubweave_superselector?(s2,s1)enddiff=[]untillcs.empty?diff<<chunks(seq1,seq2){|s|subweave_superselector?(s.first,lcs.first)}<<[lcs.shift]seq1.shiftseq2.shiftenddiff<<chunks(seq1,seq2){|s|s.empty?}diff.reject!{|c|c.empty?}Sass::Util.paths(diff).map{|p|p.flatten}enddefchunks(seq1,seq2)chunk1=[]chunk1<<seq1.shiftuntilyieldseq1chunk2=[]chunk2<<seq2.shiftuntilyieldseq2return[]ifchunk1.empty?&&chunk2.empty?return[chunk2]ifchunk1.empty?return[chunk1]ifchunk2.empty?[chunk1+chunk2,chunk2+chunk1]enddefgroup_selectors(seq)newseq=[]tail=seq.dupuntiltail.empty?head=[]beginhead<<tail.shiftendwhile!tail.empty?&&head.last.is_a?(String)||tail.first.is_a?(String)newseq<<headendreturnnewseqenddefsubweave_superselector?(sseq1,sseq2)ifsseq1.size>1# More complex selectors are never superselectors of less complex onesreturnunlesssseq2.size>1# .foo ~ .bar is a superselector of .foo + .barreturnunlesssseq1[1]=="~"?sseq2[1]!=">":sseq2[1]==sseq1[1]returnunlesssseq1.first.superselector?(sseq2.first)returntrueifsseq1.size==2returnfalseifsseq2.size==2returnsubweave_superselector?(sseq1[2..-1],sseq2[2..-1])elsifsseq2.size>1returntrueifsseq2[1]==">"&&sseq1.first.superselector?(sseq2.first)returnfalseifsseq2.size==2returnsubweave_superselector?(sseq1,sseq2[2..-1])elsesseq1.first.superselector?(sseq2.first)endenddef_hashmembers.reject{|m|m=="\n"}.hashenddef_eql?(other)other.members.reject{|m|m=="\n"}.eql?(self.members.reject{|m|m=="\n"})endendendend