blob: 2c48a77fadd57bd9186fe5f192eb88bd983c47a2 [file] [log] [blame]
# -*- coding: utf-8 -*-
module Sass
module SCSS
# A module containing regular expressions used
# for lexing tokens in an SCSS document.
# Most of these are taken from [the CSS3 spec](http://www.w3.org/TR/css3-syntax/#lexical),
# although some have been modified for various reasons.
module RX
# Takes a string and returns a CSS identifier
# that will have the value of the given string.
#
# @param str [String] The string to escape
# @return [String] The escaped string
def self.escape_ident(str)
return "" if str.empty?
return "\\#{str}" if str == '-' || str == '_'
out = ""
value = str.dup
out << value.slice!(0...1) if value =~ /^[-_]/
if value[0...1] =~ NMSTART
out << value.slice!(0...1)
else
out << escape_char(value.slice!(0...1))
end
out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
out
end
# Escapes a single character for a CSS identifier.
#
# @param c [String] The character to escape. Should have length 1
# @return [String] The escaped character
# @private
def self.escape_char(c)
return "\\%06x" % c.ord unless c =~ %r{[ -/:-~]}
"\\#{c}"
end
# Creates a Regexp from a plain text string,
# escaping all significant characters.
#
# @param str [String] The text of the regexp
# @param flags [Integer] Flags for the created regular expression
# @return [Regexp]
# @private
def self.quote(str, flags = 0)
Regexp.new(Regexp.quote(str), flags)
end
H = /[0-9a-fA-F]/
NL = /\n|\r\n|\r|\f/
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
s = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
NONASCII = /[#{s}]/
ESCAPE = /#{UNICODE}|\\[ -~#{s}]/
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
NMCHAR = /[a-zA-Z0-9_-]|#{NONASCII}|#{ESCAPE}/
STRING1 = /\"((?:[^\n\r\f\\"]|\\#{NL}|#{ESCAPE})*)\"/
STRING2 = /\'((?:[^\n\r\f\\']|\\#{NL}|#{ESCAPE})*)\'/
IDENT = /-*#{NMSTART}#{NMCHAR}*/
NAME = /#{NMCHAR}+/
STRING = /#{STRING1}|#{STRING2}/
URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
URL = /(#{URLCHAR}*)/
W = /[ \t\r\n\f]*/
VARIABLE = /(\$)(#{Sass::SCSS::RX::IDENT})/
# This is more liberal than the spec's definition,
# but that definition didn't work well with the greediness rules
RANGE = /(?:#{H}|\?){1,6}/
##
S = /[ \t\r\n\f]+/
COMMENT = %r{/\*([^*]|\*+[^/*])*\**\*/}
SINGLE_LINE_COMMENT = %r{//.*(\n[ \t]*//.*)*}
CDO = quote("<!--")
CDC = quote("-->")
INCLUDES = quote("~=")
DASHMATCH = quote("|=")
PREFIXMATCH = quote("^=")
SUFFIXMATCH = quote("$=")
SUBSTRINGMATCH = quote("*=")
HASH = /##{NAME}/
IMPORTANT = /!#{W}important/i
# A unit is like an IDENT, but disallows a hyphen followed by a digit.
# This allows "1px-2px" to be interpreted as subtraction rather than "1"
# with the unit "px-2px". It also allows "%".
UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\.?\d))*|%/
UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
NUMBER = /#{UNITLESS_NUMBER}(?:#{UNIT})?/
PERCENTAGE = /#{UNITLESS_NUMBER}%/
URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
FUNCTION = /#{IDENT}\(/
UNICODERANGE = /u\+(?:#{H}{1,6}-#{H}{1,6}|#{RANGE})/i
# Defined in http://www.w3.org/TR/css3-selectors/#lex
PLUS = /#{W}\+/
GREATER = /#{W}>/
TILDE = /#{W}~/
NOT = quote(":not(", Regexp::IGNORECASE)
# Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
# non-standard version of http://www.w3.org/TR/css3-conditional/
URL_PREFIX = /url-prefix\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
DOMAIN = /domain\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
# Custom
HEXCOLOR = /\#[0-9a-fA-F]+/
INTERP_START = /#\{/
ANY = /:(-[-\w]+-)?any\(/i
OPTIONAL = /!#{W}optional/i
IDENT_START = /-|#{NMSTART}/
IDENT_HYPHEN_INTERP = /-(?=#\{)/
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*(?=[;}]))i
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
end
end
end