sass-embedded 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/sass/extconf.rb +3 -48
- data/ext/sass/package.json +5 -0
- data/lib/sass/compile_error.rb +1 -10
- data/lib/sass/compile_result.rb +1 -5
- data/lib/sass/embedded/channel.rb +2 -2
- data/lib/sass/embedded/compile_context/function_registry.rb +85 -0
- data/lib/sass/embedded/compile_context/importer_registry.rb +99 -0
- data/lib/sass/embedded/compile_context/logger_registry.rb +45 -0
- data/lib/sass/embedded/compile_context/value_protofier.rb +237 -0
- data/lib/sass/embedded/compile_context.rb +31 -236
- data/lib/sass/embedded/compiler.rb +10 -43
- data/lib/sass/embedded/{render.rb → legacy.rb} +41 -0
- data/lib/sass/embedded/observer.rb +2 -0
- data/lib/sass/embedded/protofier.rb +91 -0
- data/lib/sass/embedded/structifier.rb +30 -0
- data/lib/sass/embedded/varint.rb +33 -0
- data/lib/sass/embedded/version.rb +1 -1
- data/lib/sass/embedded/version_context.rb +2 -3
- data/lib/sass/embedded.rb +39 -52
- data/lib/sass/embedded_protocol.rb +0 -6
- data/lib/sass/logger/source_location.rb +3 -9
- data/lib/sass/logger/source_span.rb +1 -13
- data/lib/sass/logger.rb +3 -3
- data/lib/sass/script_error.rb +5 -0
- data/lib/sass/value/argument_list.rb +24 -0
- data/lib/sass/value/boolean.rb +42 -0
- data/lib/sass/value/color.rb +213 -0
- data/lib/sass/value/function.rb +35 -0
- data/lib/sass/value/fuzzy_math.rb +81 -0
- data/lib/sass/value/list.rb +60 -0
- data/lib/sass/value/map.rb +57 -0
- data/lib/sass/value/null.rb +39 -0
- data/lib/sass/value/number/unit.rb +186 -0
- data/lib/sass/value/number.rb +272 -0
- data/lib/sass/value/string.rb +43 -0
- data/lib/sass/value.rb +92 -0
- data/lib/sass.rb +51 -48
- metadata +31 -53
- data/lib/sass/embedded/compiler/requirements.rb +0 -9
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's map type.
|
6
|
+
class Map < Sass::Value
|
7
|
+
def initialize(contents = {}) # rubocop:disable Lint/MissingSuper
|
8
|
+
@contents = contents.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :contents
|
12
|
+
|
13
|
+
def separator
|
14
|
+
contents.empty? ? nil : ','
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_map(_name = nil)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_map
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_a
|
26
|
+
contents.to_a.map { |entry| Sass::Value::List.new(entry, separator: ' ') }
|
27
|
+
end
|
28
|
+
|
29
|
+
def at(index)
|
30
|
+
if index.is_a? Numeric
|
31
|
+
index = index.floor
|
32
|
+
index = to_a.length + index if index.negative?
|
33
|
+
return nil if index.negative? || index >= to_a.length
|
34
|
+
|
35
|
+
to_a[index]
|
36
|
+
else
|
37
|
+
contents[index]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(other)
|
42
|
+
(other.is_a?(Sass::Value::Map) && other.contents == contents) ||
|
43
|
+
(contents.empty? && other.is_a?(Sass::Value::List) && other.to_a.empty?)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hash
|
47
|
+
@hash ||= contents.hash
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def to_a_length
|
53
|
+
contents.length
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's null type.
|
6
|
+
class Null < Sass::Value
|
7
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
8
|
+
@value = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :value
|
12
|
+
|
13
|
+
alias to_nil value
|
14
|
+
|
15
|
+
def to_bool
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
other.is_a?(Sass::Value::Null)
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
@hash ||= value.hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def !
|
28
|
+
Boolean::TRUE
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sass's null value.
|
32
|
+
NULL = Null.new
|
33
|
+
|
34
|
+
def self.new
|
35
|
+
NULL
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
class Number
|
6
|
+
# The {Unit} module.
|
7
|
+
module Unit
|
8
|
+
CONVERSIONS = {
|
9
|
+
# Length
|
10
|
+
'in' => {
|
11
|
+
'in' => Rational(1),
|
12
|
+
'cm' => Rational(1, 2.54),
|
13
|
+
'pc' => Rational(1, 6),
|
14
|
+
'mm' => Rational(1, 25.4),
|
15
|
+
'q' => Rational(1, 101.6),
|
16
|
+
'pt' => Rational(1, 72),
|
17
|
+
'px' => Rational(1, 96)
|
18
|
+
},
|
19
|
+
'cm' => {
|
20
|
+
'in' => Rational(2.54),
|
21
|
+
'cm' => Rational(1),
|
22
|
+
'pc' => Rational(2.54, 6),
|
23
|
+
'mm' => Rational(1, 10),
|
24
|
+
'q' => Rational(1, 40),
|
25
|
+
'pt' => Rational(2.54, 72),
|
26
|
+
'px' => Rational(2.54, 96)
|
27
|
+
},
|
28
|
+
'pc' => {
|
29
|
+
'in' => Rational(6),
|
30
|
+
'cm' => Rational(6, 2.54),
|
31
|
+
'pc' => Rational(1),
|
32
|
+
'mm' => Rational(6, 25.4),
|
33
|
+
'q' => Rational(6, 101.6),
|
34
|
+
'pt' => Rational(1, 12),
|
35
|
+
'px' => Rational(1, 16)
|
36
|
+
},
|
37
|
+
'mm' => {
|
38
|
+
'in' => Rational(25.4),
|
39
|
+
'cm' => Rational(10),
|
40
|
+
'pc' => Rational(25.4, 6),
|
41
|
+
'mm' => Rational(1),
|
42
|
+
'q' => Rational(1, 4),
|
43
|
+
'pt' => Rational(25.4, 72),
|
44
|
+
'px' => Rational(25.4, 96)
|
45
|
+
},
|
46
|
+
'q' => {
|
47
|
+
'in' => Rational(101.6),
|
48
|
+
'cm' => Rational(40),
|
49
|
+
'pc' => Rational(101.6, 6),
|
50
|
+
'mm' => Rational(4),
|
51
|
+
'q' => Rational(1),
|
52
|
+
'pt' => Rational(101.6, 72),
|
53
|
+
'px' => Rational(101.6, 96)
|
54
|
+
},
|
55
|
+
'pt' => {
|
56
|
+
'in' => Rational(72),
|
57
|
+
'cm' => Rational(72, 2.54),
|
58
|
+
'pc' => Rational(12),
|
59
|
+
'mm' => Rational(72, 25.4),
|
60
|
+
'q' => Rational(72, 101.6),
|
61
|
+
'pt' => Rational(1),
|
62
|
+
'px' => Rational(3, 4)
|
63
|
+
},
|
64
|
+
'px' => {
|
65
|
+
'in' => Rational(96),
|
66
|
+
'cm' => Rational(96, 2.54),
|
67
|
+
'pc' => Rational(16),
|
68
|
+
'mm' => Rational(96, 25.4),
|
69
|
+
'q' => Rational(96, 101.6),
|
70
|
+
'pt' => Rational(4, 3),
|
71
|
+
'px' => Rational(1)
|
72
|
+
},
|
73
|
+
|
74
|
+
# Rotation
|
75
|
+
'deg' => {
|
76
|
+
'deg' => Rational(1),
|
77
|
+
'grad' => Rational(9, 10),
|
78
|
+
'rad' => Rational(180, Math::PI),
|
79
|
+
'turn' => Rational(360)
|
80
|
+
},
|
81
|
+
'grad' => {
|
82
|
+
'deg' => Rational(10, 9),
|
83
|
+
'grad' => Rational(1),
|
84
|
+
'rad' => Rational(200, Math::PI),
|
85
|
+
'turn' => Rational(400)
|
86
|
+
},
|
87
|
+
'rad' => {
|
88
|
+
'deg' => Rational(Math::PI, 180),
|
89
|
+
'grad' => Rational(Math::PI, 200),
|
90
|
+
'rad' => Rational(1),
|
91
|
+
'turn' => Rational(2 * Math::PI)
|
92
|
+
},
|
93
|
+
'turn' => {
|
94
|
+
'deg' => Rational(1, 360),
|
95
|
+
'grad' => Rational(1, 400),
|
96
|
+
'rad' => Rational(1, 2 * Math::PI),
|
97
|
+
'turn' => Rational(1)
|
98
|
+
},
|
99
|
+
|
100
|
+
# Time
|
101
|
+
's' => {
|
102
|
+
's' => Rational(1),
|
103
|
+
'ms' => Rational(1, 1000)
|
104
|
+
},
|
105
|
+
'ms' => {
|
106
|
+
's' => Rational(1000),
|
107
|
+
'ms' => Rational(1)
|
108
|
+
},
|
109
|
+
|
110
|
+
# Frequency
|
111
|
+
'Hz' => {
|
112
|
+
'Hz' => Rational(1),
|
113
|
+
'kHz' => Rational(1000)
|
114
|
+
},
|
115
|
+
'kHz' => {
|
116
|
+
'Hz' => Rational(1, 1000),
|
117
|
+
'kHz' => Rational(1)
|
118
|
+
},
|
119
|
+
|
120
|
+
# Pixel density
|
121
|
+
'dpi' => {
|
122
|
+
'dpi' => Rational(1),
|
123
|
+
'dpcm' => Rational(2.54),
|
124
|
+
'dppx' => Rational(96)
|
125
|
+
},
|
126
|
+
'dpcm' => {
|
127
|
+
'dpi' => Rational(1, 2.54),
|
128
|
+
'dpcm' => Rational(1),
|
129
|
+
'dppx' => Rational(96, 2.54)
|
130
|
+
},
|
131
|
+
'dppx' => {
|
132
|
+
'dpi' => Rational(1, 96),
|
133
|
+
'dpcm' => Rational(2.54, 96),
|
134
|
+
'dppx' => Rational(1)
|
135
|
+
}
|
136
|
+
}.freeze
|
137
|
+
|
138
|
+
UNITS_BY_TYPE = {
|
139
|
+
time: %w[s ms],
|
140
|
+
frequency: %w[Hz kHz],
|
141
|
+
'pixel density': %w[dpi dpcm dppx]
|
142
|
+
}.freeze
|
143
|
+
|
144
|
+
TYPES_BY_UNIT = UNITS_BY_TYPE.invert
|
145
|
+
.to_a
|
146
|
+
.flat_map { |pair| pair[0].map { |key| [key, pair[1]] } }
|
147
|
+
.to_h
|
148
|
+
|
149
|
+
module_function
|
150
|
+
|
151
|
+
def conversion_factor(unit1, unit2)
|
152
|
+
return 1 if unit1 == unit2
|
153
|
+
|
154
|
+
CONVERSIONS.dig(unit1, unit2)
|
155
|
+
end
|
156
|
+
|
157
|
+
def canonicalize_units(units)
|
158
|
+
return units if units.empty?
|
159
|
+
|
160
|
+
if units.length == 1
|
161
|
+
type = TYPES_BY_UNIT[units.first]
|
162
|
+
return type.nil? ? units : [UNITS_BY_TYPE[type].first]
|
163
|
+
end
|
164
|
+
|
165
|
+
units.map do |unit|
|
166
|
+
type = TYPES_BY_UNIT[unit]
|
167
|
+
type.nil? ? units : [UNITS_BY_TYPE[type].first]
|
168
|
+
end.sort
|
169
|
+
end
|
170
|
+
|
171
|
+
def canonical_multiplier(units)
|
172
|
+
units.reduce(1) do |multiplier, unit|
|
173
|
+
multiplier * canonical_multiplier_for_unit(unit)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def canonical_multiplier_for_unit(unit)
|
178
|
+
inner_map = CONVERSIONS[unit]
|
179
|
+
inner_map.nil? ? 1 : 1 / inner_map.values.first
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
private_constant :Unit
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's number type.
|
6
|
+
class Number < Sass::Value
|
7
|
+
def initialize(value, numerator_units = [], denominator_units = []) # rubocop:disable Lint/MissingSuper
|
8
|
+
numerator_units = [numerator_units] if numerator_units.is_a?(::String)
|
9
|
+
denominator_units = [denominator_units] if denominator_units.is_a?(::String)
|
10
|
+
|
11
|
+
unless denominator_units.empty? && numerator_units.empty?
|
12
|
+
value = value.dup
|
13
|
+
numerator_units = numerator_units.dup
|
14
|
+
new_denominator_units = []
|
15
|
+
|
16
|
+
denominator_units.each do |denominator_unit|
|
17
|
+
index = numerator_units.find_index do |numerator_unit|
|
18
|
+
factor = Unit.conversion_factor(denominator_unit, numerator_unit)
|
19
|
+
if factor.nil?
|
20
|
+
false
|
21
|
+
else
|
22
|
+
value *= factor
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
if index.nil?
|
27
|
+
new_denominator_units.push(denominator_unit)
|
28
|
+
else
|
29
|
+
numerator_units.delete_at(index)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
denominator_units = new_denominator_units
|
34
|
+
end
|
35
|
+
|
36
|
+
@value = value.freeze
|
37
|
+
@numerator_units = numerator_units.freeze
|
38
|
+
@denominator_units = denominator_units.freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :value, :numerator_units, :denominator_units
|
42
|
+
|
43
|
+
def unitless?
|
44
|
+
numerator_units.empty? && denominator_units.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_unitless(name = nil)
|
48
|
+
raise error "Expected #{self} to have no units", name unless unitless?
|
49
|
+
end
|
50
|
+
|
51
|
+
def units?
|
52
|
+
!unitless?
|
53
|
+
end
|
54
|
+
|
55
|
+
def unit?(unit)
|
56
|
+
single_unit? && numerator_units.first == unit
|
57
|
+
end
|
58
|
+
|
59
|
+
def assert_unit(unit, name = nil)
|
60
|
+
raise error "Expected #{self} to have no unit \"#{unit}\"", name unless unit?(unit)
|
61
|
+
end
|
62
|
+
|
63
|
+
def integer?
|
64
|
+
FuzzyMath.integer?(value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def assert_integer(name = nil)
|
68
|
+
raise error "#{self} is not an integer", name unless integer?
|
69
|
+
|
70
|
+
to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_i
|
74
|
+
FuzzyMath.to_i(value)
|
75
|
+
end
|
76
|
+
|
77
|
+
def assert_between(min, max, name = nil)
|
78
|
+
FuzzyMath.assert_between(value, min, max, name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def compatible_with_unit?(unit)
|
82
|
+
single_unit? && !Unit.conversion_factor(numerator_units.first, unit).nil?
|
83
|
+
end
|
84
|
+
|
85
|
+
def convert(new_numerator_units, new_denominator_units, name = nil)
|
86
|
+
Number.new(convert_value(new_numerator_units, new_denominator_units, name), new_numerator_units,
|
87
|
+
new_denominator_units)
|
88
|
+
end
|
89
|
+
|
90
|
+
def convert_value(new_numerator_units, new_denominator_units, name = nil)
|
91
|
+
coerce_or_convert_value(new_numerator_units, new_denominator_units,
|
92
|
+
coerce_unitless: false,
|
93
|
+
name: name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_to_match(other, name = nil, other_name = nil)
|
97
|
+
Number.new(convert_value_to_match(other, name, other_name), other.numerator_units, other.denominator_units)
|
98
|
+
end
|
99
|
+
|
100
|
+
def convert_value_to_match(other, name = nil, other_name = nil)
|
101
|
+
coerce_or_convert_value(other.numerator_units, other.denominator_units,
|
102
|
+
coerce_unitless: false,
|
103
|
+
name: name,
|
104
|
+
other: other,
|
105
|
+
other_name: other_name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def coerce(new_numerator_units, new_denominator_units, name = nil)
|
109
|
+
Number.new(coerce_value(new_numerator_units, new_denominator_units, name), new_numerator_units,
|
110
|
+
new_denominator_units)
|
111
|
+
end
|
112
|
+
|
113
|
+
def coerce_value(new_numerator_units, new_denominator_units, name = nil)
|
114
|
+
coerce_or_convert_value(new_numerator_units, new_denominator_units,
|
115
|
+
coerce_unitless: true,
|
116
|
+
name: name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def coerce_value_to_unit(unit, name = nil)
|
120
|
+
coerce_value([unit], [], name)
|
121
|
+
end
|
122
|
+
|
123
|
+
def coerce_to_match(other, name = nil, other_name = nil)
|
124
|
+
Number.new(coerce_value_to_match(other, name, other_name), other.numerator_units, other.denominator_units)
|
125
|
+
end
|
126
|
+
|
127
|
+
def coerce_value_to_match(other, name = nil, other_name = nil)
|
128
|
+
coerce_or_convert_value(other.numerator_units, other.denominator_units,
|
129
|
+
coerce_unitless: true,
|
130
|
+
name: name,
|
131
|
+
other: other,
|
132
|
+
other_name: other_name)
|
133
|
+
end
|
134
|
+
|
135
|
+
def assert_number(_name = nil)
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
def ==(other)
|
140
|
+
return false unless other.is_a? Sass::Value::Number
|
141
|
+
|
142
|
+
return false if numerator_units.length != other.numerator_units.length ||
|
143
|
+
denominator_units.length != other.denominator_units.length
|
144
|
+
|
145
|
+
return FuzzyMath.equals(value, other.value) if unitless?
|
146
|
+
|
147
|
+
if Unit.canonicalize_units(numerator_units) != Unit.canonicalize_units(other.numerator_units) &&
|
148
|
+
Unit.canonicalize_units(denominator_units) != Unit.canonicalize_units(other.denominator_units)
|
149
|
+
return false
|
150
|
+
end
|
151
|
+
|
152
|
+
FuzzyMath.equals(
|
153
|
+
(value *
|
154
|
+
Unit.canonical_multiplier(numerator_units) /
|
155
|
+
Unit.canonical_multiplier(denominator_units)),
|
156
|
+
(other.value *
|
157
|
+
Unit.canonical_multiplier(other.numerator_units) /
|
158
|
+
Unit.canonical_multiplier(other.denominator_units))
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def hash
|
163
|
+
@hash ||= if unitless?
|
164
|
+
FuzzyMath.hash(value)
|
165
|
+
elsif single_unit?
|
166
|
+
FuzzyMath.hash(
|
167
|
+
value * Unit.canonical_multiplier_for_unit(numerator_units.first)
|
168
|
+
)
|
169
|
+
else
|
170
|
+
FuzzyMath.hash(
|
171
|
+
value * Unit.canonical_multiplier(numerator_units) / Unit.canonical_multiplier(denominator_units)
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
protected
|
177
|
+
|
178
|
+
def single_unit?
|
179
|
+
numerator_units.length == 1 && denominator_units.empty?
|
180
|
+
end
|
181
|
+
|
182
|
+
def coerce_or_convert_value(new_numerator_units, new_denominator_units,
|
183
|
+
coerce_unitless:,
|
184
|
+
name: nil,
|
185
|
+
other: nil,
|
186
|
+
other_name: nil)
|
187
|
+
if other && (other.numerator_units != new_denominator_units && other.denominator_units != new_denominator_units)
|
188
|
+
raise error "Expect #{other} to have units #{unit_string(new_numerator_units, new_denominator_units)}"
|
189
|
+
end
|
190
|
+
|
191
|
+
return value if numerator_units == new_numerator_units && denominator_units == new_denominator_units
|
192
|
+
|
193
|
+
return value if numerator_units == new_numerator_units && denominator_units == new_denominator_units
|
194
|
+
|
195
|
+
other_unitless = new_numerator_units.empty? && new_denominator_units.empty?
|
196
|
+
|
197
|
+
return value if coerce_unitless && (unitless? || other_unitless)
|
198
|
+
|
199
|
+
compatibility_error = lambda {
|
200
|
+
unless other.nil?
|
201
|
+
message = +"#{self} and"
|
202
|
+
message << " $#{other_name}:" unless other_name.nil?
|
203
|
+
message << " #{other} have incompatible units"
|
204
|
+
message << " (one has units and the other doesn't)" if unitless? || other_unitless
|
205
|
+
return error message, name
|
206
|
+
end
|
207
|
+
|
208
|
+
return error "Expected #{self} to have no units", name unless other_unitless
|
209
|
+
|
210
|
+
if new_numerator_units.length == 1 && new_denominator_units.empty?
|
211
|
+
type = Unit::TYPES_BY_UNIT[new_numerator_units.first]
|
212
|
+
return error "Expected #{self} to have a #{type} unit (#{Unit::UNITS_BY_TYPE[type].join(', ')})", name
|
213
|
+
end
|
214
|
+
|
215
|
+
unit_length = new_numerator_units.length + new_denominator_units.length
|
216
|
+
units = unit_string(new_numerator_units, new_denominator_units)
|
217
|
+
error "Expected #{self} to have unit#{unit_length > 1 ? 's' : ''} #{units}", name
|
218
|
+
}
|
219
|
+
|
220
|
+
result = value
|
221
|
+
|
222
|
+
old_numerator_units = numerator_units.dup
|
223
|
+
new_numerator_units.each do |new_numerator_unit|
|
224
|
+
index = old_numerator_units.find_index do |old_numerator_unit|
|
225
|
+
factor = Unit.conversion_factor(new_numerator_unit, old_numerator_unit)
|
226
|
+
if factor.nil?
|
227
|
+
false
|
228
|
+
else
|
229
|
+
result *= factor
|
230
|
+
true
|
231
|
+
end
|
232
|
+
end
|
233
|
+
raise compatibility_error.call if index.nil?
|
234
|
+
|
235
|
+
old_numerator_units.delete_at(index)
|
236
|
+
end
|
237
|
+
|
238
|
+
old_denominator_units = denominator_units.dup
|
239
|
+
new_denominator_units.each do |new_denominator_unit|
|
240
|
+
index = old_denominator_units.find_index do |old_denominator_unit|
|
241
|
+
factor = Unit.conversion_factor(new_denominator_unit, old_denominator_unit)
|
242
|
+
if factor.nil?
|
243
|
+
false
|
244
|
+
else
|
245
|
+
result /= factor
|
246
|
+
true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
raise compatibility_error.call if index.nil?
|
250
|
+
|
251
|
+
old_denominator_units.delete_at(index)
|
252
|
+
end
|
253
|
+
|
254
|
+
raise compatibility_error.call unless old_numerator_units.empty? && old_denominator_units.empty?
|
255
|
+
|
256
|
+
result
|
257
|
+
end
|
258
|
+
|
259
|
+
def unit_string(numerator_units, denominator_units)
|
260
|
+
if numerator_units.empty?
|
261
|
+
return 'no units' if denominator_units.empty?
|
262
|
+
|
263
|
+
return denominator_units.length == 1 ? "#{denominator_units.first}^-1" : "(#{denominator_units.join('*')})^-1"
|
264
|
+
end
|
265
|
+
|
266
|
+
return numerator_units.join('*') if denominator_units.empty?
|
267
|
+
|
268
|
+
"#{numerator_units.join('*')}/#{denominator_units.join('*')}"
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's string type.
|
6
|
+
class String < Sass::Value
|
7
|
+
def initialize(text = '', quoted: true) # rubocop:disable Lint/MissingSuper
|
8
|
+
@text = text.freeze
|
9
|
+
@quoted = quoted
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :text
|
13
|
+
|
14
|
+
def quoted?
|
15
|
+
@quoted
|
16
|
+
end
|
17
|
+
|
18
|
+
def sass_index_to_string_index(sass_index, name = nil)
|
19
|
+
index = sass_index.assert_number(name).assert_integer(name)
|
20
|
+
raise error('String index may not be 0', name) if index.zero?
|
21
|
+
|
22
|
+
if index.abs > text.length
|
23
|
+
raise error("Invalid index #{sass_index} for a string with #{text.length} characters",
|
24
|
+
name)
|
25
|
+
end
|
26
|
+
|
27
|
+
index.negative? ? text.length + index : index - 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
other.is_a?(Sass::Value::String) && other.text == text
|
32
|
+
end
|
33
|
+
|
34
|
+
def hash
|
35
|
+
@hash ||= text.hash
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert_string(_name = nil)
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/sass/value.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# The abstract base class of Sass's value types.
|
5
|
+
class Value
|
6
|
+
def to_a
|
7
|
+
[self]
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bool
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_map
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_nil
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def separator
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def bracketed?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def sass_index_to_array_index(sass_index, name = nil)
|
31
|
+
index = sass_index.assert_number(name).assert_integer(name)
|
32
|
+
raise error('List index may not be 0', name) if index.zero?
|
33
|
+
|
34
|
+
if index.abs > to_a_length
|
35
|
+
raise error("Invalid index #{sass_index} for a list with #{to_a_length} elements",
|
36
|
+
name)
|
37
|
+
end
|
38
|
+
|
39
|
+
index.negative? ? to_a_length + index : index - 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def at(index)
|
43
|
+
index < 1 && index >= -1 ? self : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](index)
|
47
|
+
at(index)
|
48
|
+
end
|
49
|
+
|
50
|
+
def assert_boolean(name = nil)
|
51
|
+
raise error("#{self} is not a boolean", name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def assert_calculation(name = nil)
|
55
|
+
raise error("#{self} is not a calculation", name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def assert_color(name = nil)
|
59
|
+
raise error("#{self} is not a color", name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert_function(name = nil)
|
63
|
+
raise error("#{self} is not a function", name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def assert_map(name = nil)
|
67
|
+
raise error("#{self} is not a map", name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_number(name = nil)
|
71
|
+
raise error("#{self} is not a number", name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def assert_string(name = nil)
|
75
|
+
raise error("#{self} is not a string", name)
|
76
|
+
end
|
77
|
+
|
78
|
+
def eql?(other)
|
79
|
+
self == other
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def to_a_length
|
85
|
+
1
|
86
|
+
end
|
87
|
+
|
88
|
+
def error(message, name = nil)
|
89
|
+
Sass::ScriptError.new name.nil? ? message : "$#{name}: #{message}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|