require'sass/script/css_parser'moduleSassmoduleSCSS# A parser for a static SCSS tree.# Parses with SCSS extensions, like nested rules and parent selectors,# but without dynamic SassScript.# This is useful for e.g. \{#parse\_selector parsing selectors}# after resolving the interpolation.classStaticParser<Parser# Parses the text as a selector.## @param filename [String, nil] The file in which the selector appears,# or nil if there is no such file.# Used for error reporting.# @return [Selector::CommaSequence] The parsed selector# @raise [Sass::SyntaxError] if there's a syntax error in the selectordefparse_selectorinit_scanner!seq=expr!(:selector_comma_sequence)expected("selector")unless@scanner.eos?seq.line=@lineseq.filename=@filenameseqend# Parses a static at-root query.## @return [(Symbol, Array<String>)] The type of the query# (`:with` or `:without`) and the values that are being filtered.# @raise [Sass::SyntaxError] if there's a syntax error in the query,# or if it doesn't take up the entire input string.defparse_static_at_root_queryinit_scanner!tok!(/\(/);sstype=tok!(/\b(without|with)\b/).to_sym;sstok!(/:/);ssdirectives=expr!(:at_root_directive_list);sstok!(/\)/)expected("@at-root query list")unless@scanner.eos?returntype,directivesenddefparse_keyframes_selectorinit_scanner!sel=expr!(:keyframes_selector)expected("keyframes selector")unless@scanner.eos?selend# @see Parser#initialize# @param allow_parent_ref [Boolean] Whether to allow the# parent-reference selector, `&`, when parsing the document.# @comment# rubocop:disable ParameterListsdefinitialize(str,filename,importer,line=1,offset=1,allow_parent_ref=true)# rubocop:enable ParameterListssuper(str,filename,importer,line,offset)@allow_parent_ref=allow_parent_refendprivatedefmoz_document_functionval=tok(URI)||tok(URL_PREFIX)||tok(DOMAIN)||function(!:allow_var)returnunlessvalss[val]enddefvariable;nil;enddefscript_value;nil;enddefinterpolation(warn_for_color=false);nil;enddefvar_expr;nil;enddefinterp_string;(s=tok(STRING))&&[s];enddefinterp_uri;(s=tok(URI))&&[s];enddefinterp_ident(ident=IDENT);(s=tok(ident))&&[s];enddefuse_css_import?;true;enddefspecial_directive(name,start_pos)returnunless%w[media import charset -moz-document].include?(name)superenddefselector_comma_sequencesel=selectorreturnunlessselselectors=[sel]ws=''whiletok(/,/)ws<<str{ss}if(sel=selector)selectors<<selifws.include?("\n")selectors[-1]=Selector::Sequence.new(["\n"]+selectors.last.members)endws=''endendSelector::CommaSequence.new(selectors)enddefselector_stringsel=selectorreturnunlessselsel.to_senddefselectorstart_pos=source_position# The combinator here allows the "> E" hackval=combinator||simple_selector_sequencereturnunlessvalnl=str{ss}.include?("\n")res=[]res<<valres<<"\n"ifnlwhile(val=combinator||simple_selector_sequence)res<<valres<<"\n"ifstr{ss}.include?("\n")endseq=Selector::Sequence.new(res.compact)ifseq.members.any?{|sseq|sseq.is_a?(Selector::SimpleSequence)&&sseq.subject?}location=" of #{@filename}"if@filenameSass::Util.sass_warn<<MESSAGE
DEPRECATION WARNING on line #{start_pos.line}, column #{start_pos.offset}#{location}:
The subject selector operator "!" is deprecated and will be removed in a future release.
This operator has been replaced by ":has()" in the CSS spec.
For example: #{seq.subjectless}MESSAGEendseqenddefcombinatortok(PLUS)||tok(GREATER)||tok(TILDE)||reference_combinatorenddefreference_combinatorreturnunlesstok(/\//)res='/'ns,name=expr!(:qualified_name)res<<ns<<'|'ifnsres<<name<<tok!(/\//)resenddefsimple_selector_sequencestart_pos=source_positione=element_name||id_selector||class_selector||placeholder_selector||attrib||pseudo||parent_selectorreturnunlesseres=[e]# The tok(/\*/) allows the "E*" hackwhile(v=id_selector||class_selector||placeholder_selector||attrib||pseudo||(tok(/\*/)&&Selector::Universal.new(nil)))res<<vendpos=@scanner.posline=@lineif(sel=str?{simple_selector_sequence})@scanner.pos=pos@line=linebegin# If we see "*E", don't force a throw because this could be the# "*prop: val" hack.expected('"{"')ifres.length==1&&res[0].is_a?(Selector::Universal)throw_error{expected('"{"')}rescueSass::SyntaxError=>ee.message<<"\n\n\"#{sel}\" may only be used at the beginning of a compound selector."raiseeendendSelector::SimpleSequence.new(res,tok(/!/),range(start_pos))enddefparent_selectorreturnunless@allow_parent_ref&&tok(/&/)Selector::Parent.new(tok(NAME))enddefclass_selectorreturnunlesstok(/\./)@expected="class name"Selector::Class.new(tok!(IDENT))enddefid_selectorreturnunlesstok(/#(?!\{)/)@expected="id name"Selector::Id.new(tok!(NAME))enddefplaceholder_selectorreturnunlesstok(/%/)@expected="placeholder name"Selector::Placeholder.new(tok!(IDENT))enddefelement_namens,name=Sass::Util.destructure(qualified_name(:allow_star_name))returnunlessns||nameifname=='*'Selector::Universal.new(ns)elseSelector::Element.new(name,ns)endenddefqualified_name(allow_star_name=false)name=tok(IDENT)||tok(/\*/)||(tok?(/\|/)&&"")returnunlessnamereturnnil,nameunlesstok(/\|/)returnname,tok!(IDENT)unlessallow_star_name@expected="identifier or *"returnname,tok(IDENT)||tok!(/\*/)enddefattribreturnunlesstok(/\[/)ssns,name=attrib_name!ssop=tok(/=/)||tok(INCLUDES)||tok(DASHMATCH)||tok(PREFIXMATCH)||tok(SUFFIXMATCH)||tok(SUBSTRINGMATCH)ifop@expected="identifier or string"ssval=tok(IDENT)||tok!(STRING)ssendflags=tok(IDENT)||tok(STRING)tok!(/\]/)Selector::Attribute.new(name,ns,op,val,flags)enddefattrib_name!if(name_or_ns=tok(IDENT))# E, E|Eiftok(/\|(?!=)/)ns=name_or_nsname=tok(IDENT)elsename=name_or_nsendelse# *|E or |Ens=tok(/\*/)||""tok!(/\|/)name=tok!(IDENT)endreturnns,nameendSELECTOR_PSEUDO_CLASSES=%w[not matches current any has host host-context].to_setPREFIXED_SELECTOR_PSEUDO_CLASSES=%w[nth-child nth-last-child].to_setdefpseudos=tok(/::?/)returnunlesss@expected="pseudoclass or pseudoelement"name=tok!(IDENT)iftok(/\(/)ssdeprefixed=deprefix(name)ifs==':'&&SELECTOR_PSEUDO_CLASSES.include?(deprefixed)sel=selector_comma_sequenceelsifs==':'&&PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)arg,sel=prefixed_selector_pseudoelsearg=expr!(:pseudo_args)endtok!(/\)/)endSelector::Pseudo.new(s==':'?:class::element,name,arg,sel)enddefpseudo_argsarg=expr!(:pseudo_expr)whiletok(/,/)arg<<','<<str{ss}arg.concatexpr!(:pseudo_expr)endargenddefpseudo_exprres=pseudo_expr_tokenreturnunlessresres<<str{ss}while(e=pseudo_expr_token)res<<e<<str{ss}endresenddefpseudo_expr_tokentok(PLUS)||tok(/[-*]/)||tok(NUMBER)||tok(STRING)||tok(IDENT)enddefprefixed_selector_pseudoprefix=strdoexpr=str{expr!(:a_n_plus_b)}ssreturnexpr,nilunlesstok(/of/)ssendreturnprefix,expr!(:selector_comma_sequence)enddefa_n_plus_bif(parity=tok(/even|odd/i))returnparityendiftok(/[+-]?[0-9]+/)ssreturntrueunlesstok(/n/)elsereturnunlesstok(/[+-]?n/i)endssreturntrueunlesstok(/[+-]/)ss@expected="number"tok!(/[0-9]+/)trueenddefkeyframes_selectorssstrdoreturnunlesskeyframes_selector_componentsswhiletok(/,/)ssexpr!(:keyframes_selector_component)ssendendenddefkeyframes_selector_componenttok(IDENT)||tok(PERCENTAGE)end@sass_script_parser=Class.new(Sass::Script::CssParser)@sass_script_parser.send(:include,ScriptParser)endendend