File: list.rb

package info (click to toggle)
ruby-sass 3.7.4-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 2,784 kB
  • sloc: ruby: 32,443; sh: 26; makefile: 25
file content (134 lines) | stat: -rw-r--r-- 3,840 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
module Sass::Script::Value
  # A SassScript object representing a CSS list.
  # This includes both comma-separated lists and space-separated lists.
  class List < Base
    # The Ruby array containing the contents of the list.
    #
    # @return [Array<Value>]
    attr_reader :value
    alias_method :to_a, :value

    # The operator separating the values of the list.
    # Either `:comma` or `:space`.
    #
    # @return [Symbol]
    attr_reader :separator

    # Whether the list is surrounded by square brackets.
    #
    # @return [Boolean]
    attr_reader :bracketed

    # Creates a new list.
    #
    # @param value [Array<Value>] See \{#value}
    # @param separator [Symbol] See \{#separator}
    # @param bracketed [Boolean] See \{#bracketed}
    def initialize(value, separator: nil, bracketed: false)
      super(value)
      @separator = separator
      @bracketed = bracketed
    end

    # @see Value#options=
    def options=(options)
      super
      value.each {|v| v.options = options}
    end

    # @see Value#eq
    def eq(other)
      Sass::Script::Value::Bool.new(
        other.is_a?(List) && value == other.value &&
        separator == other.separator && bracketed == other.bracketed)
    end

    def hash
      @hash ||= [value, separator, bracketed].hash
    end

    # @see Value#to_s
    def to_s(opts = {})
      if !bracketed && value.empty?
        raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
      end

      members = value.
        reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
        map {|e| e.to_s(opts)}

      contents = members.join(sep_str)
      bracketed ? "[#{contents}]" : contents
    end

    # @see Value#to_sass
    def to_sass(opts = {})
      return bracketed ? "[]" : "()" if value.empty?
      members = value.map do |v|
        if element_needs_parens?(v)
          "(#{v.to_sass(opts)})"
        else
          v.to_sass(opts)
        end
      end

      if separator == :comma && members.length == 1
        return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
      end

      contents = members.join(sep_str(nil))
      bracketed ? "[#{contents}]" : contents
    end

    # @see Value#to_h
    def to_h
      return {} if value.empty?
      super
    end

    # @see Value#inspect
    def inspect
      (bracketed ? '[' : '(') +
        value.map {|e| e.inspect}.join(sep_str(nil)) +
        (bracketed ? ']' : ')')
    end

    # Asserts an index is within the list.
    #
    # @private
    #
    # @param list [Sass::Script::Value::List] The list for which the index should be checked.
    # @param n [Sass::Script::Value::Number] The index being checked.
    def self.assert_valid_index(list, n)
      if !n.int? || n.to_i == 0
        raise ArgumentError.new("List index #{n} must be a non-zero integer")
      elsif list.to_a.size == 0
        raise ArgumentError.new("List index is #{n} but list has no items")
      elsif n.to_i.abs > (size = list.to_a.size)
        raise ArgumentError.new(
          "List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
      end
    end

    private

    def element_needs_parens?(element)
      if element.is_a?(List)
        return false if element.value.length < 2
        return false if element.bracketed
        precedence = Sass::Script::Parser.precedence_of(separator || :space)
        return Sass::Script::Parser.precedence_of(element.separator || :space) <= precedence
      end

      return false unless separator == :space
      return false unless element.is_a?(Sass::Script::Tree::UnaryOperation)
      element.operator == :minus || element.operator == :plus
    end

    def sep_str(opts = options)
      return ' ' if separator == :space
      return ',' if opts && opts[:style] == :compressed
      ', '
    end
  end
end