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.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
@@ -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
@@ -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