# class Sass::SCSS::StaticParser

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.

### Constants

PREFIXED_SELECTOR_PSEUDO_CLASSES
SELECTOR_PSEUDO_CLASSES
SELECTOR_PSEUDO_ELEMENTS

### Public Class Methods

new(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true) click to toggle source

@see Parser#initialize @param allow_parent_ref [Boolean] Whether to allow the

    parent-reference selector, `&`, when parsing the document.

@comment

    rubocop:disable ParameterLists

Calls superclass method Sass::SCSS::Parser.new

    # File lib/sass/scss/static_parser.rb, line 56
    def initialize(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true)
      # rubocop:enable ParameterLists
      super(str, filename, importer, line, offset)
      @allow_parent_ref = allow_parent_ref
    end

### Public Instance Methods

parse_keyframes_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 44
    def parse_keyframes_selector
      init_scanner!
      sel = expr!(:keyframes_selector)
      expected("keyframes selector") unless @scanner.eos?
      sel
    end

parse_selector() click to toggle source

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 selector

    # File lib/sass/scss/static_parser.rb, line 18
    def parse_selector
      init_scanner!
      seq = expr!(:selector_comma_sequence)
      expected("selector") unless @scanner.eos?
      seq.line = @line
      seq.filename = @filename
      seq
    end

parse_static_at_root_query() click to toggle source

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.

    # File lib/sass/scss/static_parser.rb, line 33
    def parse_static_at_root_query
      init_scanner!
      tok!(/\(/); ss
      type = tok!(/\b(without|with)\b/).to_sym; ss
      tok!(/:/); ss
      directives = expr!(:at_root_directive_list); ss
      tok!(/\)/)
      expected("@at-root query list") unless @scanner.eos?
      return type, directives
    end

### Private Instance Methods

a_n_plus_b() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 314
    def a_n_plus_b
      if (parity = tok(/even|odd/i))
        return parity
      end

      if tok(/[+-]?[0-9]+/)
        ss
        return true unless tok(/n/)
      else
        return unless tok(/[+-]?n/i)
      end
      ss

      return true unless tok(/[+-]/)
      ss
      @expected = "number"
      tok!(/[0-9]+/)
      true
    end

attrib() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 233
    def attrib
      return unless tok(/\[/)
      ss
      ns, name = attrib_name!
      ss

      op = tok(/=/) ||
           tok(INCLUDES) ||
           tok(DASHMATCH) ||
           tok(PREFIXMATCH) ||
           tok(SUFFIXMATCH) ||
           tok(SUBSTRINGMATCH)
      if op
        @expected = "identifier or string"
        ss
        val = tok(IDENT) || tok!(STRING)
        ss
      end
      flags = tok(IDENT) || tok(STRING)
      tok!(/\]/)

      Selector::Attribute.new(name, ns, op, val, flags)
    end

attrib_name!() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 257
    def attrib_name!
      if (name_or_ns = tok(IDENT))
        # E, E|E
        if tok(/\|(?!=)/)
          ns = name_or_ns
          name = tok(IDENT)
        else
          name = name_or_ns
        end
      else
        # *|E or |E
        ns = tok(/\*/) || ""
        tok!(/\|/)
        name = tok!(IDENT)
      end
      return ns, name
    end

class_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 194
    def class_selector
      return unless tok(/\./)
      @expected = "class name"
      Selector::Class.new(tok!(IDENT))
    end

combinator() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 137
    def combinator
      tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
    end

element_name() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 212
    def element_name
      ns, name = Sass::Util.destructure(qualified_name(:allow_star_name))
      return unless ns || name

      if name == '*'
        Selector::Universal.new(ns)
      else
        Selector::Element.new(name, ns)
      end
    end

id_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 200
    def id_selector
      return unless tok(/#(?!\{)/)
      @expected = "id name"
      Selector::Id.new(tok!(NAME))
    end

interp_ident(ident = IDENT) click to toggle source

    # File lib/sass/scss/static_parser.rb, line 77
    def interp_ident(ident = IDENT); (s = tok(ident)) && [s]; end

interp_string() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 75
    def interp_string; (s = tok(STRING)) && [s]; end

interp_uri() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 76
    def interp_uri; (s = tok(URI)) && [s]; end

interpolation(warn_for_color = false) click to toggle source

    # File lib/sass/scss/static_parser.rb, line 73
    def interpolation(warn_for_color = false); nil; end

keyframes_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 334
    def keyframes_selector
      ss
      str do
        return unless keyframes_selector_component
        ss
        while tok(/,/)
          ss
          expr!(:keyframes_selector_component)
          ss
        end
      end
    end

keyframes_selector_component() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 347
    def keyframes_selector_component
      tok(IDENT) || tok(PERCENTAGE)
    end

moz_document_function() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 64
    def moz_document_function
      val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(false)
      return unless val
      ss
      [val]
    end

parent_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 189
    def parent_selector
      return unless @allow_parent_ref && tok(/&/)
      Selector::Parent.new(tok(NAME))
    end

placeholder_selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 206
    def placeholder_selector
      return unless tok(/%/)
      @expected = "placeholder name"
      Selector::Placeholder.new(tok!(IDENT))
    end

prefixed_selector_pseudo() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 304
    def prefixed_selector_pseudo
      prefix = str do
        expr = str {expr!(:a_n_plus_b)}
        ss
        return expr, nil unless tok(/of/)
        ss
      end
      return prefix, expr!(:selector_comma_sequence)
    end

pseudo() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 281
    def pseudo
      s = tok(/::?/)
      return unless s
      @expected = "pseudoclass or pseudoelement"
      name = tok!(IDENT)
      if tok(/\(/)
        ss
        deprefixed = deprefix(name)
        if s == ':' && SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
          sel = selector_comma_sequence
        elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
          arg, sel = prefixed_selector_pseudo
        elsif s == '::' && SELECTOR_PSEUDO_ELEMENTS.include?(deprefixed)
          sel = selector_comma_sequence
        else
          arg = expr!(:declaration_value).join
        end

        tok!(/\)/)
      end
      Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
    end

qualified_name(allow_star_name = false) click to toggle source

    # File lib/sass/scss/static_parser.rb, line 223
    def qualified_name(allow_star_name = false)
      name = tok(IDENT) || tok(/\*/) || (tok?(/\|/) && "")
      return unless name
      return nil, name unless tok(/\|/)

      return name, tok!(IDENT) unless allow_star_name
      @expected = "identifier or *"
      return name, tok(IDENT) || tok!(/\*/)
    end

reference_combinator() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 141
          def reference_combinator
            return unless tok(%r{/})
            res = '/'
            ns, name = expr!(:qualified_name)
            res << ns << '|' if ns
            res << name << tok!(%r{/})

            location = " of #{@filename}" if @filename
            Sass::Util.sass_warn <<MESSAGE
    DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
    The reference combinator #{res} is deprecated and will be removed in a future release.
    MESSAGE

            res
          end

script_value() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 72
    def script_value; nil; end

selector() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 108
          def selector
            start_pos = source_position
            # The combinator here allows the "> E" hack
            val = combinator || simple_selector_sequence
            return unless val
            nl = str {ss}.include?("\n")
            res = []
            res << val
            res << "\n" if nl

            while (val = combinator || simple_selector_sequence)
              res << val
              res << "\n" if str {ss}.include?("\n")
            end
            seq = Selector::Sequence.new(res.compact)

            if seq.members.any? {|sseq| sseq.is_a?(Selector::SimpleSequence) && sseq.subject?}
              location = " of #{@filename}" if @filename
              Sass::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}
    MESSAGE
            end

            seq
          end

selector_comma_sequence() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 85
    def selector_comma_sequence
      sel = selector
      return unless sel
      selectors = [sel]
      ws = ''
      while tok(/,/)
        ws << str {ss}
        next unless (sel = selector)
        selectors << sel
        if ws.include?("\n")
          selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
        end
        ws = ''
      end
      Selector::CommaSequence.new(selectors)
    end

selector_string() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 102
    def selector_string
      sel = selector
      return unless sel
      sel.to_s
    end

simple_selector_sequence() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 157
    def simple_selector_sequence
      start_pos = source_position
      e = element_name || id_selector || class_selector || placeholder_selector || attrib ||
          pseudo || parent_selector
      return unless e
      res = [e]

      # The tok(/\*/) allows the "E*" hack
      while (v = id_selector || class_selector || placeholder_selector ||
                 attrib || pseudo || (tok(/\*/) && Selector::Universal.new(nil)))
        res << v
      end

      pos = @scanner.pos
      line = @line
      if (sel = str? {simple_selector_sequence})
        @scanner.pos = pos
        @line = line
        begin
          # If we see "*E", don't force a throw because this could be the
          # "*prop: val" hack.
          expected('"{"') if res.length == 1 && res[0].is_a?(Selector::Universal)
          throw_error {expected('"{"')}
        rescue Sass::SyntaxError => e
          e.message << "\n\n\"#{sel}\" may only be used at the beginning of a compound selector."
          raise e
        end
      end

      Selector::SimpleSequence.new(res, tok(/!/), range(start_pos))
    end

special_directive(name, start_pos) click to toggle source
Calls superclass method Sass::SCSS::Parser#special_directive

    # File lib/sass/scss/static_parser.rb, line 80
    def special_directive(name, start_pos)
      return unless %w(media import charset -moz-document).include?(name)
      super
    end

use_css_import?() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 78
    def use_css_import?; true; end

var_expr() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 74
    def var_expr; nil; end

variable() click to toggle source

    # File lib/sass/scss/static_parser.rb, line 71
    def variable; nil; end