oreorenasass 3.4.4 → 3.4.5
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/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
data/lib/sass/selector/pseudo.rb
DELETED
@@ -1,256 +0,0 @@
|
|
1
|
-
module Sass
|
2
|
-
module Selector
|
3
|
-
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
|
4
|
-
# selector. It can have arguments (e.g. `:nth-child(2n+1)`) which can
|
5
|
-
# contain selectors (e.g. `:nth-child(2n+1 of .foo)`).
|
6
|
-
class Pseudo < Simple
|
7
|
-
# Some pseudo-class-syntax selectors are actually considered
|
8
|
-
# pseudo-elements and must be treated differently. This is a list of such
|
9
|
-
# selectors.
|
10
|
-
#
|
11
|
-
# @return [Set<String>]
|
12
|
-
ACTUALLY_ELEMENTS = %w[after before first-line first-letter].to_set
|
13
|
-
|
14
|
-
# Like \{#type}, but returns the type of selector this looks like, rather
|
15
|
-
# than the type it is semantically. This only differs from type for
|
16
|
-
# selectors in \{ACTUALLY\_ELEMENTS}.
|
17
|
-
#
|
18
|
-
# @return [Symbol]
|
19
|
-
attr_reader :syntactic_type
|
20
|
-
|
21
|
-
# The name of the selector.
|
22
|
-
#
|
23
|
-
# @return [String]
|
24
|
-
attr_reader :name
|
25
|
-
|
26
|
-
# The argument to the selector,
|
27
|
-
# or `nil` if no argument was given.
|
28
|
-
#
|
29
|
-
# @return [String, nil]
|
30
|
-
attr_reader :arg
|
31
|
-
|
32
|
-
# The selector argument, or `nil` if no selector exists.
|
33
|
-
#
|
34
|
-
# If this and \{#arg\} are both set, \{#arg\} is considered a non-selector
|
35
|
-
# prefix.
|
36
|
-
#
|
37
|
-
# @return [CommaSequence]
|
38
|
-
attr_reader :selector
|
39
|
-
|
40
|
-
# @param syntactic_type [Symbol] See \{#syntactic_type}
|
41
|
-
# @param name [String] See \{#name}
|
42
|
-
# @param arg [nil, String] See \{#arg}
|
43
|
-
# @param selector [nil, CommaSequence] See \{#selector}
|
44
|
-
def initialize(syntactic_type, name, arg, selector)
|
45
|
-
@syntactic_type = syntactic_type
|
46
|
-
@name = name
|
47
|
-
@arg = arg
|
48
|
-
@selector = selector
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns a copy of this with \{#selector} set to \{#new\_selector}.
|
52
|
-
#
|
53
|
-
# @param new_selector [CommaSequence]
|
54
|
-
# @return [CommaSequence]
|
55
|
-
def with_selector(new_selector)
|
56
|
-
Pseudo.new(syntactic_type, name, arg, CommaSequence.new(new_selector.members.map do |seq|
|
57
|
-
next seq unless seq.members.length == 1
|
58
|
-
sseq = seq.members.first
|
59
|
-
next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
|
60
|
-
sel = sseq.members.first
|
61
|
-
next seq unless sel.is_a?(Pseudo) && sel.selector
|
62
|
-
|
63
|
-
case normalized_name
|
64
|
-
when 'not'
|
65
|
-
# In theory, if there's a nested :not its contents should be
|
66
|
-
# unified with the return value. For example, if :not(.foo)
|
67
|
-
# extends .bar, :not(.bar) should become .foo:not(.bar). However,
|
68
|
-
# this is a narrow edge case and supporting it properly would make
|
69
|
-
# this code and the code calling it a lot more complicated, so
|
70
|
-
# it's not supported for now.
|
71
|
-
next [] unless sel.normalized_name == 'matches'
|
72
|
-
sel.selector.members
|
73
|
-
when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
|
74
|
-
# As above, we could theoretically support :not within :matches, but
|
75
|
-
# doing so would require this method and its callers to handle much
|
76
|
-
# more complex cases that likely aren't worth the pain.
|
77
|
-
next [] unless sel.name == name && sel.arg == arg
|
78
|
-
sel.selector.members
|
79
|
-
when 'has', 'host', 'host-context'
|
80
|
-
# We can't expand nested selectors here, because each layer adds an
|
81
|
-
# additional layer of semantics. For example, `:has(:has(img))`
|
82
|
-
# doesn't match `<div><img></div>` but `:has(img)` does.
|
83
|
-
sel
|
84
|
-
else
|
85
|
-
[]
|
86
|
-
end
|
87
|
-
end.flatten))
|
88
|
-
end
|
89
|
-
|
90
|
-
# The type of the selector. `:class` if this is a pseudoclass selector,
|
91
|
-
# `:element` if it's a pseudoelement.
|
92
|
-
#
|
93
|
-
# @return [Symbol]
|
94
|
-
def type
|
95
|
-
ACTUALLY_ELEMENTS.include?(normalized_name) ? :element : syntactic_type
|
96
|
-
end
|
97
|
-
|
98
|
-
# Like \{#name\}, but without any vendor prefix.
|
99
|
-
#
|
100
|
-
# @return [String]
|
101
|
-
def normalized_name
|
102
|
-
@normalized_name ||= name.gsub(/^-[a-zA-Z0-9]+-/, '')
|
103
|
-
end
|
104
|
-
|
105
|
-
# @see Selector#to_s
|
106
|
-
def to_s
|
107
|
-
res = (syntactic_type == :class ? ":" : "::") + @name
|
108
|
-
if @arg || @selector
|
109
|
-
res << "("
|
110
|
-
res << @arg.strip if @arg
|
111
|
-
res << " " if @arg && @selector
|
112
|
-
res << @selector.to_s if @selector
|
113
|
-
res << ")"
|
114
|
-
end
|
115
|
-
res
|
116
|
-
end
|
117
|
-
|
118
|
-
# Returns `nil` if this is a pseudoelement selector
|
119
|
-
# and `sels` contains a pseudoelement selector different than this one.
|
120
|
-
#
|
121
|
-
# @see SimpleSequence#unify
|
122
|
-
def unify(sels)
|
123
|
-
return if type == :element && sels.any? do |sel|
|
124
|
-
sel.is_a?(Pseudo) && sel.type == :element &&
|
125
|
-
(sel.name != name || sel.arg != arg || sel.selector != selector)
|
126
|
-
end
|
127
|
-
super
|
128
|
-
end
|
129
|
-
|
130
|
-
# Returns whether or not this selector matches all elements
|
131
|
-
# that the given selector matches (as well as possibly more).
|
132
|
-
#
|
133
|
-
# @example
|
134
|
-
# (.foo).superselector?(.foo.bar) #=> true
|
135
|
-
# (.foo).superselector?(.bar) #=> false
|
136
|
-
# @param their_sseq [SimpleSequence]
|
137
|
-
# @param parents [Array<SimpleSequence, String>] The parent selectors of `their_sseq`, if any.
|
138
|
-
# @return [Boolean]
|
139
|
-
def superselector?(their_sseq, parents = [])
|
140
|
-
case normalized_name
|
141
|
-
when 'matches', 'any'
|
142
|
-
# :matches can be a superselector of another selector in one of two
|
143
|
-
# ways. Either its constituent selectors can be a superset of those of
|
144
|
-
# another :matches in the other selector, or any of its constituent
|
145
|
-
# selectors can individually be a superselector of the other selector.
|
146
|
-
(their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
|
147
|
-
next false unless their_sel.is_a?(Pseudo)
|
148
|
-
next false unless their_sel.name == name
|
149
|
-
selector.superselector?(their_sel.selector)
|
150
|
-
end || selector.members.any? do |our_seq|
|
151
|
-
their_seq = Sequence.new(parents + [their_sseq])
|
152
|
-
our_seq.superselector?(their_seq)
|
153
|
-
end
|
154
|
-
when 'has', 'host', 'host-context'
|
155
|
-
# Like :matches, :has (et al) can be a superselector of another
|
156
|
-
# selector if its constituent selectors are a superset of those of
|
157
|
-
# another :has in the other selector. However, the :matches other case
|
158
|
-
# doesn't work, because :has refers to nested elements.
|
159
|
-
(their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
|
160
|
-
next false unless their_sel.is_a?(Pseudo)
|
161
|
-
next false unless their_sel.name == name
|
162
|
-
selector.superselector?(their_sel.selector)
|
163
|
-
end
|
164
|
-
when 'not'
|
165
|
-
selector.members.all? do |our_seq|
|
166
|
-
their_sseq.members.any? do |their_sel|
|
167
|
-
if their_sel.is_a?(Element) || their_sel.is_a?(Id)
|
168
|
-
# `:not(a)` is a superselector of `h1` and `:not(#foo)` is a
|
169
|
-
# superselector of `#bar`.
|
170
|
-
our_sseq = our_seq.members.last
|
171
|
-
next false unless our_sseq.is_a?(SimpleSequence)
|
172
|
-
our_sseq.members.any? do |our_sel|
|
173
|
-
our_sel.class == their_sel.class && our_sel != their_sel
|
174
|
-
end
|
175
|
-
else
|
176
|
-
next false unless their_sel.is_a?(Pseudo)
|
177
|
-
next false unless their_sel.name == name
|
178
|
-
# :not(X) is a superselector of :not(Y) exactly when Y is a
|
179
|
-
# superselector of X.
|
180
|
-
their_sel.selector.superselector?(CommaSequence.new([our_seq]))
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
when 'current'
|
185
|
-
(their_sseq.selector_pseudo_classes['current'] || []).any? do |their_current|
|
186
|
-
next false if their_current.name != name
|
187
|
-
# Explicitly don't check for nested superselector relationships
|
188
|
-
# here. :current(.foo) isn't always a superselector of
|
189
|
-
# :current(.foo.bar), since it matches the *innermost* ancestor of
|
190
|
-
# the current element that matches the selector. For example:
|
191
|
-
#
|
192
|
-
# <div class="foo bar">
|
193
|
-
# <p class="foo">
|
194
|
-
# <span>current element</span>
|
195
|
-
# </p>
|
196
|
-
# </div>
|
197
|
-
#
|
198
|
-
# Here :current(.foo) would match the p element and *not* the div
|
199
|
-
# element, whereas :current(.foo.bar) would match the div and not
|
200
|
-
# the p.
|
201
|
-
selector == their_current.selector
|
202
|
-
end
|
203
|
-
when 'nth-child', 'nth-last-child'
|
204
|
-
their_sseq.members.any? do |their_sel|
|
205
|
-
# This misses a few edge cases. For example, `:nth-child(n of X)`
|
206
|
-
# is a superselector of `X`, and `:nth-child(2n of X)` is a
|
207
|
-
# superselector of `:nth-child(4n of X)`. These seem rare enough
|
208
|
-
# not to be worth worrying about, though.
|
209
|
-
next false unless their_sel.is_a?(Pseudo)
|
210
|
-
next false unless their_sel.name == name
|
211
|
-
next false unless their_sel.arg == arg
|
212
|
-
selector.superselector?(their_sel.selector)
|
213
|
-
end
|
214
|
-
else
|
215
|
-
throw "[BUG] Unknown selector pseudo class #{name}"
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# @see AbstractSequence#specificity
|
220
|
-
def specificity
|
221
|
-
return 1 if type == :element
|
222
|
-
return SPECIFICITY_BASE unless selector
|
223
|
-
@specificity ||=
|
224
|
-
if normalized_name == 'not'
|
225
|
-
min = 0
|
226
|
-
max = 0
|
227
|
-
selector.members.each do |seq|
|
228
|
-
spec = seq.specificity
|
229
|
-
if spec.is_a?(Range)
|
230
|
-
min = Sass::Util.max(spec.begin, min)
|
231
|
-
max = Sass::Util.max(spec.end, max)
|
232
|
-
else
|
233
|
-
min = Sass::Util.max(spec, min)
|
234
|
-
max = Sass::Util.max(spec, max)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
min == max ? max : (min..max)
|
238
|
-
else
|
239
|
-
min = 0
|
240
|
-
max = 0
|
241
|
-
selector.members.each do |seq|
|
242
|
-
spec = seq.specificity
|
243
|
-
if spec.is_a?(Range)
|
244
|
-
min = Sass::Util.min(spec.begin, min)
|
245
|
-
max = Sass::Util.max(spec.end, max)
|
246
|
-
else
|
247
|
-
min = Sass::Util.min(spec, min)
|
248
|
-
max = Sass::Util.max(spec, max)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
min == max ? max : (min..max)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
data/lib/sass/source/map.rb
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
module Sass::Source
|
2
|
-
class Map
|
3
|
-
# A mapping from one source range to another. Indicates that `input` was
|
4
|
-
# compiled to `output`.
|
5
|
-
#
|
6
|
-
# @!attribute input
|
7
|
-
# @return [Sass::Source::Range] The source range in the input document.
|
8
|
-
#
|
9
|
-
# @!attribute output
|
10
|
-
# @return [Sass::Source::Range] The source range in the output document.
|
11
|
-
class Mapping < Struct.new(:input, :output)
|
12
|
-
# @return [String] A string representation of the mapping.
|
13
|
-
def inspect
|
14
|
-
"#{input.inspect} => #{output.inspect}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# The mapping data ordered by the location in the target.
|
19
|
-
#
|
20
|
-
# @return [Array<Mapping>]
|
21
|
-
attr_reader :data
|
22
|
-
|
23
|
-
def initialize
|
24
|
-
@data = []
|
25
|
-
end
|
26
|
-
|
27
|
-
# Adds a new mapping from one source range to another. Multiple invocations
|
28
|
-
# of this method should have each `output` range come after all previous ranges.
|
29
|
-
#
|
30
|
-
# @param input [Sass::Source::Range]
|
31
|
-
# The source range in the input document.
|
32
|
-
# @param output [Sass::Source::Range]
|
33
|
-
# The source range in the output document.
|
34
|
-
def add(input, output)
|
35
|
-
@data.push(Mapping.new(input, output))
|
36
|
-
end
|
37
|
-
|
38
|
-
# Shifts all output source ranges forward one or more lines.
|
39
|
-
#
|
40
|
-
# @param delta [Fixnum] The number of lines to shift the ranges forward.
|
41
|
-
def shift_output_lines(delta)
|
42
|
-
return if delta == 0
|
43
|
-
@data.each do |m|
|
44
|
-
m.output.start_pos.line += delta
|
45
|
-
m.output.end_pos.line += delta
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Shifts any output source ranges that lie on the first line forward one or
|
50
|
-
# more characters on that line.
|
51
|
-
#
|
52
|
-
# @param delta [Fixnum] The number of characters to shift the ranges
|
53
|
-
# forward.
|
54
|
-
def shift_output_offsets(delta)
|
55
|
-
return if delta == 0
|
56
|
-
@data.each do |m|
|
57
|
-
break if m.output.start_pos.line > 1
|
58
|
-
m.output.start_pos.offset += delta
|
59
|
-
m.output.end_pos.offset += delta if m.output.end_pos.line > 1
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns the standard JSON representation of the source map.
|
64
|
-
#
|
65
|
-
# If the `:css_uri` option isn't specified, the `:css_path` and
|
66
|
-
# `:sourcemap_path` options must both be specified. Any options may also be
|
67
|
-
# specified alongside the `:css_uri` option. If `:css_uri` isn't specified,
|
68
|
-
# it will be inferred from `:css_path` and `:sourcemap_path` using the
|
69
|
-
# assumption that the local file system has the same layout as the server.
|
70
|
-
#
|
71
|
-
# Regardless of which options are passed to this method, source stylesheets
|
72
|
-
# that are imported using a non-default importer will only be linked to in
|
73
|
-
# the source map if their importers implement
|
74
|
-
# \{Sass::Importers::Base#public\_url\}.
|
75
|
-
#
|
76
|
-
# @option options :css_uri [String]
|
77
|
-
# The publicly-visible URI of the CSS output file.
|
78
|
-
# @option options :css_path [String]
|
79
|
-
# The local path of the CSS output file.
|
80
|
-
# @option options :sourcemap_path [String]
|
81
|
-
# The (eventual) local path of the sourcemap file.
|
82
|
-
# @option options :type [Symbol]
|
83
|
-
# `:auto` (default), `:file`, or `:inline`.
|
84
|
-
# @return [String] The JSON string.
|
85
|
-
# @raise [ArgumentError] If neither `:css_uri` nor `:css_path` and
|
86
|
-
# `:sourcemap_path` are specified.
|
87
|
-
# @comment
|
88
|
-
# rubocop:disable MethodLength
|
89
|
-
def to_json(options)
|
90
|
-
css_uri, css_path, sourcemap_path =
|
91
|
-
options[:css_uri], options[:css_path], options[:sourcemap_path]
|
92
|
-
unless css_uri || (css_path && sourcemap_path)
|
93
|
-
raise ArgumentError.new("Sass::Source::Map#to_json requires either " \
|
94
|
-
"the :css_uri option or both the :css_path and :soucemap_path options.")
|
95
|
-
end
|
96
|
-
css_path &&= Sass::Util.pathname(Sass::Util.absolute_path(css_path))
|
97
|
-
sourcemap_path &&= Sass::Util.pathname(Sass::Util.absolute_path(sourcemap_path))
|
98
|
-
css_uri ||= Sass::Util.file_uri_from_path(css_path.relative_path_from(sourcemap_path.dirname))
|
99
|
-
|
100
|
-
result = "{\n"
|
101
|
-
write_json_field(result, "version", 3, true)
|
102
|
-
|
103
|
-
source_uri_to_id = {}
|
104
|
-
id_to_source_uri = {}
|
105
|
-
id_to_contents = {} if options[:type] == :inline
|
106
|
-
next_source_id = 0
|
107
|
-
line_data = []
|
108
|
-
segment_data_for_line = []
|
109
|
-
|
110
|
-
# These track data necessary for the delta coding.
|
111
|
-
previous_target_line = nil
|
112
|
-
previous_target_offset = 1
|
113
|
-
previous_source_line = 1
|
114
|
-
previous_source_offset = 1
|
115
|
-
previous_source_id = 0
|
116
|
-
|
117
|
-
@data.each do |m|
|
118
|
-
file, importer = m.input.file, m.input.importer
|
119
|
-
|
120
|
-
if options[:type] == :inline
|
121
|
-
source_uri = file
|
122
|
-
else
|
123
|
-
sourcemap_dir = sourcemap_path && sourcemap_path.dirname.to_s
|
124
|
-
sourcemap_dir = nil if options[:type] == :file
|
125
|
-
source_uri = importer && importer.public_url(file, sourcemap_dir)
|
126
|
-
next unless source_uri
|
127
|
-
end
|
128
|
-
|
129
|
-
current_source_id = source_uri_to_id[source_uri]
|
130
|
-
unless current_source_id
|
131
|
-
current_source_id = next_source_id
|
132
|
-
next_source_id += 1
|
133
|
-
|
134
|
-
source_uri_to_id[source_uri] = current_source_id
|
135
|
-
id_to_source_uri[current_source_id] = source_uri
|
136
|
-
|
137
|
-
if options[:type] == :inline
|
138
|
-
id_to_contents[current_source_id] =
|
139
|
-
importer.find(file, {}).instance_variable_get('@template')
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
[
|
144
|
-
[m.input.start_pos, m.output.start_pos],
|
145
|
-
[m.input.end_pos, m.output.end_pos]
|
146
|
-
].each do |source_pos, target_pos|
|
147
|
-
if previous_target_line != target_pos.line
|
148
|
-
line_data.push(segment_data_for_line.join(",")) unless segment_data_for_line.empty?
|
149
|
-
(target_pos.line - 1 - (previous_target_line || 0)).times {line_data.push("")}
|
150
|
-
previous_target_line = target_pos.line
|
151
|
-
previous_target_offset = 1
|
152
|
-
segment_data_for_line = []
|
153
|
-
end
|
154
|
-
|
155
|
-
# `segment` is a data chunk for a single position mapping.
|
156
|
-
segment = ""
|
157
|
-
|
158
|
-
# Field 1: zero-based starting offset.
|
159
|
-
segment << Sass::Util.encode_vlq(target_pos.offset - previous_target_offset)
|
160
|
-
previous_target_offset = target_pos.offset
|
161
|
-
|
162
|
-
# Field 2: zero-based index into the "sources" list.
|
163
|
-
segment << Sass::Util.encode_vlq(current_source_id - previous_source_id)
|
164
|
-
previous_source_id = current_source_id
|
165
|
-
|
166
|
-
# Field 3: zero-based starting line in the original source.
|
167
|
-
segment << Sass::Util.encode_vlq(source_pos.line - previous_source_line)
|
168
|
-
previous_source_line = source_pos.line
|
169
|
-
|
170
|
-
# Field 4: zero-based starting offset in the original source.
|
171
|
-
segment << Sass::Util.encode_vlq(source_pos.offset - previous_source_offset)
|
172
|
-
previous_source_offset = source_pos.offset
|
173
|
-
|
174
|
-
segment_data_for_line.push(segment)
|
175
|
-
|
176
|
-
previous_target_line = target_pos.line
|
177
|
-
end
|
178
|
-
end
|
179
|
-
line_data.push(segment_data_for_line.join(","))
|
180
|
-
write_json_field(result, "mappings", line_data.join(";"))
|
181
|
-
|
182
|
-
source_names = []
|
183
|
-
(0...next_source_id).each {|id| source_names.push(id_to_source_uri[id].to_s)}
|
184
|
-
write_json_field(result, "sources", source_names)
|
185
|
-
|
186
|
-
if options[:type] == :inline
|
187
|
-
write_json_field(result, "sourcesContent",
|
188
|
-
(0...next_source_id).map {|id| id_to_contents[id]})
|
189
|
-
end
|
190
|
-
|
191
|
-
write_json_field(result, "names", [])
|
192
|
-
write_json_field(result, "file", css_uri)
|
193
|
-
|
194
|
-
result << "\n}"
|
195
|
-
result
|
196
|
-
end
|
197
|
-
# @comment
|
198
|
-
# rubocop:enable MethodLength
|
199
|
-
|
200
|
-
private
|
201
|
-
|
202
|
-
def write_json_field(out, name, value, is_first = false)
|
203
|
-
out << (is_first ? "" : ",\n") <<
|
204
|
-
"\"" <<
|
205
|
-
Sass::Util.json_escape_string(name) <<
|
206
|
-
"\": " <<
|
207
|
-
Sass::Util.json_value_of(value)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|