sass 3.2.7 → 3.3.0.rc.1
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.
- data/MIT-LICENSE +2 -2
- data/README.md +14 -2
- data/Rakefile +25 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/lib/sass/cache_stores/base.rb +4 -2
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +2 -6
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +1 -0
- data/lib/sass/css.rb +10 -10
- data/lib/sass/engine.rb +403 -150
- data/lib/sass/environment.rb +136 -57
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +123 -39
- data/lib/sass/features.rb +41 -0
- data/lib/sass/importers/base.rb +33 -2
- data/lib/sass/importers/deprecated_path.rb +45 -0
- data/lib/sass/importers/filesystem.rb +25 -14
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +3 -3
- data/lib/sass/logger/log_level.rb +4 -6
- data/lib/sass/media.rb +19 -19
- data/lib/sass/plugin/compiler.rb +141 -101
- data/lib/sass/plugin/configuration.rb +18 -22
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +24 -8
- data/lib/sass/plugin.rb +4 -2
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script/css_lexer.rb +9 -4
- data/lib/sass/script/css_parser.rb +6 -2
- data/lib/sass/script/functions.rb +1343 -590
- data/lib/sass/script/lexer.rb +84 -52
- data/lib/sass/script/parser.rb +217 -97
- data/lib/sass/script/tree/funcall.rb +290 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
- data/lib/sass/script/tree/list_literal.rb +80 -0
- data/lib/sass/script/tree/literal.rb +47 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
- data/lib/sass/script/tree/selector.rb +30 -0
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +16 -0
- data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
- data/lib/sass/script/value/base.rb +248 -0
- data/lib/sass/script/value/bool.rb +36 -0
- data/lib/sass/script/{color.rb → value/color.rb} +239 -195
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +119 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +45 -0
- data/lib/sass/script/{number.rb → value/number.rb} +91 -65
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +11 -0
- data/lib/sass/script.rb +35 -8
- data/lib/sass/scss/css_parser.rb +2 -1
- data/lib/sass/scss/parser.rb +338 -170
- data/lib/sass/scss/rx.rb +5 -6
- data/lib/sass/scss/script_lexer.rb +1 -0
- data/lib/sass/scss/script_parser.rb +1 -0
- data/lib/sass/scss/static_parser.rb +23 -6
- data/lib/sass/selector/abstract_sequence.rb +2 -2
- data/lib/sass/selector/comma_sequence.rb +21 -16
- data/lib/sass/selector/sequence.rb +60 -34
- data/lib/sass/selector/simple.rb +11 -12
- data/lib/sass/selector/simple_sequence.rb +55 -33
- data/lib/sass/selector.rb +52 -48
- data/lib/sass/source/map.rb +211 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +120 -0
- data/lib/sass/supports.rb +12 -13
- data/lib/sass/tree/at_root_node.rb +82 -0
- 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 +13 -2
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +13 -6
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +5 -4
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +4 -5
- data/lib/sass/tree/media_node.rb +4 -14
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +21 -8
- data/lib/sass/tree/node.rb +29 -12
- data/lib/sass/tree/prop_node.rb +38 -18
- data/lib/sass/tree/return_node.rb +3 -2
- data/lib/sass/tree/root_node.rb +19 -3
- data/lib/sass/tree/rule_node.rb +25 -17
- data/lib/sass/tree/supports_node.rb +0 -13
- data/lib/sass/tree/trace_node.rb +2 -1
- data/lib/sass/tree/variable_node.rb +9 -3
- data/lib/sass/tree/visitors/base.rb +6 -6
- data/lib/sass/tree/visitors/check_nesting.rb +12 -9
- data/lib/sass/tree/visitors/convert.rb +63 -38
- data/lib/sass/tree/visitors/cssize.rb +63 -23
- data/lib/sass/tree/visitors/deep_copy.rb +6 -5
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +256 -151
- data/lib/sass/tree/visitors/set_options.rb +6 -6
- data/lib/sass/tree/visitors/to_css.rb +231 -81
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util/multibyte_string_scanner.rb +2 -0
- data/lib/sass/util/normalized_map.rb +65 -0
- data/lib/sass/util/ordered_hash.rb +188 -0
- data/lib/sass/util/subset_map.rb +3 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +220 -34
- data/lib/sass/version.rb +9 -9
- data/lib/sass.rb +14 -7
- data/test/sass/compiler_test.rb +213 -0
- data/test/sass/conversion_test.rb +235 -9
- data/test/sass/engine_test.rb +230 -60
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +215 -147
- data/test/sass/functions_test.rb +584 -99
- data/test/sass/importer_test.rb +165 -17
- data/test/sass/plugin_test.rb +19 -13
- data/test/sass/script_conversion_test.rb +40 -0
- data/test/sass/script_test.rb +231 -21
- data/test/sass/scss/css_test.rb +14 -5
- data/test/sass/scss/scss_test.rb +1266 -66
- data/test/sass/source_map_test.rb +879 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/util/normalized_map_test.rb +30 -0
- data/test/sass/util_test.rb +90 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +7 -2
- metadata +316 -291
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -231
- data/lib/sass/script/list.rb +0 -84
- data/lib/sass/script/literal.rb +0 -239
- data/lib/sass/script/null.rb +0 -34
- data/lib/sass/script/variable.rb +0 -58
- data/test/Gemfile +0 -3
- data/vendor/listen/CHANGELOG.md +0 -221
- data/vendor/listen/CONTRIBUTING.md +0 -38
- data/vendor/listen/Gemfile +0 -30
- data/vendor/listen/Guardfile +0 -8
- data/vendor/listen/LICENSE +0 -20
- data/vendor/listen/README.md +0 -315
- data/vendor/listen/Rakefile +0 -47
- data/vendor/listen/Vagrantfile +0 -96
- data/vendor/listen/lib/listen/adapter.rb +0 -214
- data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
- data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
- data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
- data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
- data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/directory_record.rb +0 -371
- data/vendor/listen/lib/listen/listener.rb +0 -225
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/lib/listen/turnstile.rb +0 -28
- data/vendor/listen/lib/listen/version.rb +0 -3
- data/vendor/listen/lib/listen.rb +0 -40
- data/vendor/listen/listen.gemspec +0 -22
- data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
- data/vendor/listen/spec/listen/listener_spec.rb +0 -169
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
- data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
- data/vendor/listen/spec/listen_spec.rb +0 -73
- data/vendor/listen/spec/spec_helper.rb +0 -21
- data/vendor/listen/spec/support/adapter_helper.rb +0 -629
- data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
- data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
- data/vendor/listen/spec/support/listeners_helper.rb +0 -156
- data/vendor/listen/spec/support/platform_helper.rb +0 -15
data/lib/sass/selector.rb
CHANGED
|
@@ -21,8 +21,6 @@ module Sass
|
|
|
21
21
|
# The base used for calculating selector specificity. The spec says this
|
|
22
22
|
# should be "sufficiently high"; it's extremely unlikely that any single
|
|
23
23
|
# selector sequence will contain 1,000 simple selectors.
|
|
24
|
-
#
|
|
25
|
-
# @type [Fixnum]
|
|
26
24
|
SPECIFICITY_BASE = 1_000
|
|
27
25
|
|
|
28
26
|
# A parent-referencing selector (`&` in Sass).
|
|
@@ -47,10 +45,10 @@ module Sass
|
|
|
47
45
|
class Class < Simple
|
|
48
46
|
# The class name.
|
|
49
47
|
#
|
|
50
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
48
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
51
49
|
attr_reader :name
|
|
52
50
|
|
|
53
|
-
# @param name [Array<String, Sass::Script::Node>] The class name
|
|
51
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The class name
|
|
54
52
|
def initialize(name)
|
|
55
53
|
@name = name
|
|
56
54
|
end
|
|
@@ -70,10 +68,10 @@ module Sass
|
|
|
70
68
|
class Id < Simple
|
|
71
69
|
# The id name.
|
|
72
70
|
#
|
|
73
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
71
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
74
72
|
attr_reader :name
|
|
75
73
|
|
|
76
|
-
# @param name [Array<String, Sass::Script::Node>] The id name
|
|
74
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The id name
|
|
77
75
|
def initialize(name)
|
|
78
76
|
@name = name
|
|
79
77
|
end
|
|
@@ -88,7 +86,7 @@ module Sass
|
|
|
88
86
|
#
|
|
89
87
|
# @see Selector#unify
|
|
90
88
|
def unify(sels)
|
|
91
|
-
return if sels.any? {|sel2| sel2.is_a?(Id) &&
|
|
89
|
+
return if sels.any? {|sel2| sel2.is_a?(Id) && name != sel2.name}
|
|
92
90
|
super
|
|
93
91
|
end
|
|
94
92
|
|
|
@@ -105,10 +103,10 @@ module Sass
|
|
|
105
103
|
class Placeholder < Simple
|
|
106
104
|
# The placeholder name.
|
|
107
105
|
#
|
|
108
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
106
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
109
107
|
attr_reader :name
|
|
110
108
|
|
|
111
|
-
# @param name [Array<String, Sass::Script::Node>] The placeholder name
|
|
109
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The placeholder name
|
|
112
110
|
def initialize(name)
|
|
113
111
|
@name = name
|
|
114
112
|
end
|
|
@@ -120,7 +118,7 @@ module Sass
|
|
|
120
118
|
|
|
121
119
|
# @see AbstractSequence#specificity
|
|
122
120
|
def specificity
|
|
123
|
-
|
|
121
|
+
SPECIFICITY_BASE
|
|
124
122
|
end
|
|
125
123
|
end
|
|
126
124
|
|
|
@@ -131,10 +129,10 @@ module Sass
|
|
|
131
129
|
# `[""]` means no namespace,
|
|
132
130
|
# `["*"]` means any namespace.
|
|
133
131
|
#
|
|
134
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
|
132
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
|
135
133
|
attr_reader :namespace
|
|
136
134
|
|
|
137
|
-
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
135
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
|
138
136
|
def initialize(namespace)
|
|
139
137
|
@namespace = namespace
|
|
140
138
|
end
|
|
@@ -195,7 +193,7 @@ module Sass
|
|
|
195
193
|
class Element < Simple
|
|
196
194
|
# The element name.
|
|
197
195
|
#
|
|
198
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
196
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
199
197
|
attr_reader :name
|
|
200
198
|
|
|
201
199
|
# The selector namespace.
|
|
@@ -203,11 +201,11 @@ module Sass
|
|
|
203
201
|
# `[""]` means no namespace,
|
|
204
202
|
# `["*"]` means any namespace.
|
|
205
203
|
#
|
|
206
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
|
204
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
|
207
205
|
attr_reader :namespace
|
|
208
206
|
|
|
209
|
-
# @param name [Array<String, Sass::Script::Node>] The element name
|
|
210
|
-
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
207
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The element name
|
|
208
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
|
211
209
|
def initialize(name, namespace)
|
|
212
210
|
@name = name
|
|
213
211
|
@namespace = namespace
|
|
@@ -262,10 +260,10 @@ module Sass
|
|
|
262
260
|
class Interpolation < Simple
|
|
263
261
|
# The script to run.
|
|
264
262
|
#
|
|
265
|
-
# @return [Sass::Script::Node]
|
|
263
|
+
# @return [Sass::Script::Tree::Node]
|
|
266
264
|
attr_reader :script
|
|
267
265
|
|
|
268
|
-
# @param script [Sass::Script::Node] The script to run
|
|
266
|
+
# @param script [Sass::Script::Tree::Node] The script to run
|
|
269
267
|
def initialize(script)
|
|
270
268
|
@script = script
|
|
271
269
|
end
|
|
@@ -288,7 +286,7 @@ module Sass
|
|
|
288
286
|
class Attribute < Simple
|
|
289
287
|
# The attribute name.
|
|
290
288
|
#
|
|
291
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
289
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
292
290
|
attr_reader :name
|
|
293
291
|
|
|
294
292
|
# The attribute namespace.
|
|
@@ -296,7 +294,7 @@ module Sass
|
|
|
296
294
|
# `[""]` means no namespace,
|
|
297
295
|
# `["*"]` means any namespace.
|
|
298
296
|
#
|
|
299
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
|
297
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
|
300
298
|
attr_reader :namespace
|
|
301
299
|
|
|
302
300
|
# The matching operator, e.g. `"="` or `"^="`.
|
|
@@ -306,20 +304,23 @@ module Sass
|
|
|
306
304
|
|
|
307
305
|
# The right-hand side of the operator.
|
|
308
306
|
#
|
|
309
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
307
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
310
308
|
attr_reader :value
|
|
311
309
|
|
|
312
310
|
# Flags for the attribute selector (e.g. `i`).
|
|
313
311
|
#
|
|
314
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
312
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
315
313
|
attr_reader :flags
|
|
316
314
|
|
|
317
|
-
# @param name [Array<String, Sass::Script::Node>] The attribute name
|
|
318
|
-
# @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
|
|
315
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The attribute name
|
|
316
|
+
# @param namespace [Array<String, Sass::Script::Tree::Node>, nil] See \{#namespace}
|
|
319
317
|
# @param operator [String] The matching operator, e.g. `"="` or `"^="`
|
|
320
|
-
# @param value [Array<String, Sass::Script::Node>] See \{#value}
|
|
321
|
-
# @param
|
|
318
|
+
# @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
|
|
319
|
+
# @param flags [Array<String, Sass::Script::Tree::Node>] See \{#flags}
|
|
320
|
+
# @comment
|
|
321
|
+
# rubocop:disable ParameterLists
|
|
322
322
|
def initialize(name, namespace, operator, value, flags)
|
|
323
|
+
# rubocop:enable ParameterLists
|
|
323
324
|
@name = name
|
|
324
325
|
@namespace = namespace
|
|
325
326
|
@operator = operator
|
|
@@ -346,23 +347,23 @@ module Sass
|
|
|
346
347
|
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
|
|
347
348
|
# It can have arguments (e.g. `:nth-child(2n+1)`).
|
|
348
349
|
class Pseudo < Simple
|
|
349
|
-
#
|
|
350
|
-
#
|
|
351
|
-
#
|
|
350
|
+
# Some psuedo-class-syntax selectors are actually considered
|
|
351
|
+
# pseudo-elements and must be treated differently. This is a list of such
|
|
352
|
+
# selectors
|
|
352
353
|
#
|
|
353
|
-
# @return [
|
|
354
|
-
|
|
354
|
+
# @return [Array<String>]
|
|
355
|
+
ACTUALLY_ELEMENTS = %w[after before first-line first-letter]
|
|
355
356
|
|
|
356
|
-
#
|
|
357
|
-
#
|
|
358
|
-
#
|
|
357
|
+
# Like \{#type}, but returns the type of selector this looks like, rather
|
|
358
|
+
# than the type it is semantically. This only differs from type for
|
|
359
|
+
# selectors in \{ACTUALLY\_ELEMENTS}.
|
|
359
360
|
#
|
|
360
|
-
# @return [
|
|
361
|
-
|
|
361
|
+
# @return [Symbol]
|
|
362
|
+
attr_reader :syntactic_type
|
|
362
363
|
|
|
363
364
|
# The name of the selector.
|
|
364
365
|
#
|
|
365
|
-
# @return [Array<String, Sass::Script::Node>]
|
|
366
|
+
# @return [Array<String, Sass::Script::Tree::Node>]
|
|
366
367
|
attr_reader :name
|
|
367
368
|
|
|
368
369
|
# The argument to the selector,
|
|
@@ -372,26 +373,30 @@ module Sass
|
|
|
372
373
|
# Note that this should not include SassScript nodes
|
|
373
374
|
# after resolution has taken place.
|
|
374
375
|
#
|
|
375
|
-
# @return [Array<String, Sass::Script::Node>, nil]
|
|
376
|
+
# @return [Array<String, Sass::Script::Tree::Node>, nil]
|
|
376
377
|
attr_reader :arg
|
|
377
378
|
|
|
378
379
|
# @param type [Symbol] See \{#type}
|
|
379
|
-
# @param name [Array<String, Sass::Script::Node>] The name of the selector
|
|
380
|
-
# @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
|
|
380
|
+
# @param name [Array<String, Sass::Script::Tree::Node>] The name of the selector
|
|
381
|
+
# @param arg [nil, Array<String, Sass::Script::Tree::Node>] The argument to the selector,
|
|
381
382
|
# or nil if no argument was given
|
|
382
383
|
def initialize(type, name, arg)
|
|
383
|
-
@
|
|
384
|
+
@syntactic_type = type
|
|
384
385
|
@name = name
|
|
385
386
|
@arg = arg
|
|
386
387
|
end
|
|
387
388
|
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
# The type of the selector. `:class` if this is a pseudoclass selector,
|
|
390
|
+
# `:element` if it's a pseudoelement.
|
|
391
|
+
#
|
|
392
|
+
# @return [Symbol]
|
|
393
|
+
def type
|
|
394
|
+
ACTUALLY_ELEMENTS.include?(name.first) ? :element : syntactic_type
|
|
390
395
|
end
|
|
391
396
|
|
|
392
397
|
# @see Selector#to_a
|
|
393
398
|
def to_a
|
|
394
|
-
res = [
|
|
399
|
+
res = [syntactic_type == :class ? ":" : "::"] + @name
|
|
395
400
|
(res << "(").concat(Sass::Util.strip_string_array(@arg)) << ")" if @arg
|
|
396
401
|
res
|
|
397
402
|
end
|
|
@@ -403,9 +408,8 @@ module Sass
|
|
|
403
408
|
def unify(sels)
|
|
404
409
|
return if type == :element && sels.any? do |sel|
|
|
405
410
|
sel.is_a?(Pseudo) && sel.type == :element &&
|
|
406
|
-
(sel.name !=
|
|
411
|
+
(sel.name != name || sel.arg != arg)
|
|
407
412
|
end
|
|
408
|
-
return sels + [self] if final?
|
|
409
413
|
super
|
|
410
414
|
end
|
|
411
415
|
|
|
@@ -428,8 +432,8 @@ module Sass
|
|
|
428
432
|
# @return [Selector::Sequence]
|
|
429
433
|
attr_reader :selector
|
|
430
434
|
|
|
431
|
-
# @param [String] The name of the pseudoclass
|
|
432
|
-
# @param [Selector::CommaSequence] The selector argument
|
|
435
|
+
# @param name [String] The name of the pseudoclass
|
|
436
|
+
# @param selector [Selector::CommaSequence] The selector argument
|
|
433
437
|
def initialize(name, selector)
|
|
434
438
|
@name = name
|
|
435
439
|
@selector = selector
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module Sass::Source
|
|
4
|
+
class Map
|
|
5
|
+
# A mapping from one source range to another. Indicates that `input` was
|
|
6
|
+
# compiled to `output`.
|
|
7
|
+
#
|
|
8
|
+
# @!attribute input
|
|
9
|
+
# @return [Sass::Source::Range] The source range in the input document.
|
|
10
|
+
#
|
|
11
|
+
# @!attribute output
|
|
12
|
+
# @return [Sass::Source::Range] The source range in the output document.
|
|
13
|
+
class Mapping < Struct.new(:input, :output)
|
|
14
|
+
# @return [String] A string representation of the mapping.
|
|
15
|
+
def inspect
|
|
16
|
+
"#{input.inspect} => #{output.inspect}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The mapping data ordered by the location in the target.
|
|
21
|
+
#
|
|
22
|
+
# @return [Array<Mapping>]
|
|
23
|
+
attr_reader :data
|
|
24
|
+
|
|
25
|
+
def initialize
|
|
26
|
+
@data = []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Adds a new mapping from one source range to another. Multiple invocations
|
|
30
|
+
# of this method should have each `output` range come after all previous ranges.
|
|
31
|
+
#
|
|
32
|
+
# @param input [Sass::Source::Range]
|
|
33
|
+
# The source range in the input document.
|
|
34
|
+
# @param output [Sass::Source::Range]
|
|
35
|
+
# The source range in the output document.
|
|
36
|
+
def add(input, output)
|
|
37
|
+
@data.push(Mapping.new(input, output))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Shifts all output source ranges forward one or more lines.
|
|
41
|
+
#
|
|
42
|
+
# @param delta [Fixnum] The number of lines to shift the ranges forward.
|
|
43
|
+
def shift_output_lines(delta)
|
|
44
|
+
return if delta == 0
|
|
45
|
+
@data.each do |m|
|
|
46
|
+
m.output.start_pos.line += delta
|
|
47
|
+
m.output.end_pos.line += delta
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Shifts any output source ranges that lie on the first line forward one or
|
|
52
|
+
# more characters on that line.
|
|
53
|
+
#
|
|
54
|
+
# @param delta [Fixnum] The number of characters to shift the ranges
|
|
55
|
+
# forward.
|
|
56
|
+
def shift_output_offsets(delta)
|
|
57
|
+
return if delta == 0
|
|
58
|
+
@data.each do |m|
|
|
59
|
+
break if m.output.start_pos.line > 1
|
|
60
|
+
m.output.start_pos.offset += delta
|
|
61
|
+
m.output.end_pos.offset += delta if m.output.end_pos.line > 1
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns the standard JSON representation of the source map.
|
|
66
|
+
#
|
|
67
|
+
# If the `:css_uri` option isn't specified, the `:css_path` and
|
|
68
|
+
# `:sourcemap_path` options must both be specified. Any options may also be
|
|
69
|
+
# specified alongside the `:css_uri` option. If `:css_uri` isn't specified,
|
|
70
|
+
# it will be inferred from `:css_path` and `:sourcemap_path` using the
|
|
71
|
+
# assumption that the local file system has the same layout as the server.
|
|
72
|
+
#
|
|
73
|
+
# If any source stylesheets use the default filesystem importer, sourcemap
|
|
74
|
+
# generation will fail unless the `:sourcemap_path` option is specified.
|
|
75
|
+
# The layout of the local file system is assumed to be the same as the
|
|
76
|
+
# layout of the server for the purposes of linking to source stylesheets
|
|
77
|
+
# that use the filesystem importer.
|
|
78
|
+
#
|
|
79
|
+
# Regardless of which options are passed to this method, source stylesheets
|
|
80
|
+
# that are imported using a non-default importer will only be linked to in
|
|
81
|
+
# the source map if their importers implement
|
|
82
|
+
# \{Sass::Importers::Base#public\_url\}.
|
|
83
|
+
#
|
|
84
|
+
# @option options :css_uri [String]
|
|
85
|
+
# The publicly-visible URI of the CSS output file.
|
|
86
|
+
# @option options :css_path [String]
|
|
87
|
+
# The local path of the CSS output file.
|
|
88
|
+
# @option options :sourcemap_path [String]
|
|
89
|
+
# The (eventual) local path of the sourcemap file.
|
|
90
|
+
# @return [String] The JSON string.
|
|
91
|
+
# @raise [ArgumentError] If neither `:css_uri` nor `:css_path` and
|
|
92
|
+
# `:sourcemap_path` are specified.
|
|
93
|
+
# @comment
|
|
94
|
+
# rubocop:disable MethodLength
|
|
95
|
+
def to_json(options)
|
|
96
|
+
css_uri, css_path, sourcemap_path =
|
|
97
|
+
[:css_uri, :css_path, :sourcemap_path].map {|o| options[o]}
|
|
98
|
+
unless css_uri || (css_path && sourcemap_path)
|
|
99
|
+
raise ArgumentError.new("Sass::Source::Map#to_json requires either " +
|
|
100
|
+
"the :css_uri option or both the :css_path and :soucemap_path options.")
|
|
101
|
+
end
|
|
102
|
+
css_path &&= Pathname.pwd.join(Pathname.new(css_path)).cleanpath
|
|
103
|
+
sourcemap_path &&= Pathname.pwd.join(Pathname.new(sourcemap_path)).cleanpath
|
|
104
|
+
css_uri ||= css_path.relative_path_from(sourcemap_path.dirname).to_s
|
|
105
|
+
|
|
106
|
+
result = "{\n"
|
|
107
|
+
write_json_field(result, "version", "3", true)
|
|
108
|
+
|
|
109
|
+
source_uri_to_id = {}
|
|
110
|
+
id_to_source_uri = {}
|
|
111
|
+
next_source_id = 0
|
|
112
|
+
line_data = []
|
|
113
|
+
segment_data_for_line = []
|
|
114
|
+
no_public_url = Set.new
|
|
115
|
+
|
|
116
|
+
# These track data necessary for the delta coding.
|
|
117
|
+
previous_target_line = nil
|
|
118
|
+
previous_target_offset = 1
|
|
119
|
+
previous_source_line = 1
|
|
120
|
+
previous_source_offset = 1
|
|
121
|
+
previous_source_id = 0
|
|
122
|
+
|
|
123
|
+
@data.each do |m|
|
|
124
|
+
file, importer = m.input.file, m.input.importer
|
|
125
|
+
unless (source_uri = importer && importer.public_url(file))
|
|
126
|
+
if importer.is_a?(Sass::Importers::Filesystem) && sourcemap_path
|
|
127
|
+
file_path = Pathname.new(importer.root).join(file)
|
|
128
|
+
source_uri = file_path.relative_path_from(sourcemap_path.dirname).to_s
|
|
129
|
+
elsif no_public_url.include?(file)
|
|
130
|
+
next
|
|
131
|
+
else
|
|
132
|
+
no_public_url << file
|
|
133
|
+
Sass::Util.sass_warn <<WARNING
|
|
134
|
+
WARNING: Couldn't determine public URL for "#{file}" while generating sourcemap.
|
|
135
|
+
Without a public URL, there's nothing for the source map to link to.
|
|
136
|
+
Custom importers should define the #public_url method.
|
|
137
|
+
WARNING
|
|
138
|
+
next
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
current_source_id = source_uri_to_id[source_uri]
|
|
143
|
+
unless current_source_id
|
|
144
|
+
current_source_id = next_source_id
|
|
145
|
+
next_source_id += 1
|
|
146
|
+
|
|
147
|
+
source_uri_to_id[source_uri] = current_source_id
|
|
148
|
+
id_to_source_uri[current_source_id] = source_uri
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
[
|
|
152
|
+
[m.input.start_pos, m.output.start_pos],
|
|
153
|
+
[m.input.end_pos, m.output.end_pos]
|
|
154
|
+
].each do |source_pos, target_pos|
|
|
155
|
+
if previous_target_line != target_pos.line
|
|
156
|
+
line_data.push(segment_data_for_line.join(",")) unless segment_data_for_line.empty?
|
|
157
|
+
(target_pos.line - 1 - (previous_target_line || 0)).times {line_data.push("")}
|
|
158
|
+
previous_target_line = target_pos.line
|
|
159
|
+
previous_target_offset = 1
|
|
160
|
+
segment_data_for_line = []
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# `segment` is a data chunk for a single position mapping.
|
|
164
|
+
segment = ""
|
|
165
|
+
|
|
166
|
+
# Field 1: zero-based starting offset.
|
|
167
|
+
segment << Sass::Util.encode_vlq(target_pos.offset - previous_target_offset)
|
|
168
|
+
previous_target_offset = target_pos.offset
|
|
169
|
+
|
|
170
|
+
# Field 2: zero-based index into the "sources" list.
|
|
171
|
+
segment << Sass::Util.encode_vlq(current_source_id - previous_source_id)
|
|
172
|
+
previous_source_id = current_source_id
|
|
173
|
+
|
|
174
|
+
# Field 3: zero-based starting line in the original source.
|
|
175
|
+
segment << Sass::Util.encode_vlq(source_pos.line - previous_source_line)
|
|
176
|
+
previous_source_line = source_pos.line
|
|
177
|
+
|
|
178
|
+
# Field 4: zero-based starting offset in the original source.
|
|
179
|
+
segment << Sass::Util.encode_vlq(source_pos.offset - previous_source_offset)
|
|
180
|
+
previous_source_offset = source_pos.offset
|
|
181
|
+
|
|
182
|
+
segment_data_for_line.push(segment)
|
|
183
|
+
|
|
184
|
+
previous_target_line = target_pos.line
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
line_data.push(segment_data_for_line.join(","))
|
|
188
|
+
write_json_field(result, "mappings", line_data.join(";"))
|
|
189
|
+
|
|
190
|
+
source_names = []
|
|
191
|
+
(0...next_source_id).each {|id| source_names.push(id_to_source_uri[id].to_s)}
|
|
192
|
+
write_json_field(result, "sources", source_names)
|
|
193
|
+
write_json_field(result, "file", css_uri)
|
|
194
|
+
|
|
195
|
+
result << "\n}"
|
|
196
|
+
result
|
|
197
|
+
end
|
|
198
|
+
# @comment
|
|
199
|
+
# rubocop:enable MethodLength
|
|
200
|
+
|
|
201
|
+
private
|
|
202
|
+
|
|
203
|
+
def write_json_field(out, name, value, is_first = false)
|
|
204
|
+
out << (is_first ? "" : ",\n") <<
|
|
205
|
+
"\"" <<
|
|
206
|
+
Sass::Util.json_escape_string(name) <<
|
|
207
|
+
"\": " <<
|
|
208
|
+
Sass::Util.json_value_of(value)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Sass::Source
|
|
2
|
+
class Position
|
|
3
|
+
# The one-based line of the document associated with the position.
|
|
4
|
+
#
|
|
5
|
+
# @return [Fixnum]
|
|
6
|
+
attr_accessor :line
|
|
7
|
+
|
|
8
|
+
# The one-based offset in the line of the document associated with the
|
|
9
|
+
# position.
|
|
10
|
+
#
|
|
11
|
+
# @return [Fixnum]
|
|
12
|
+
attr_accessor :offset
|
|
13
|
+
|
|
14
|
+
# @param line [Fixnum] The source line
|
|
15
|
+
# @param offset [Fixnum] The source offset
|
|
16
|
+
def initialize(line, offset)
|
|
17
|
+
@line = line
|
|
18
|
+
@offset = offset
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [String] A string representation of the source position.
|
|
22
|
+
def inspect
|
|
23
|
+
"#{line.inspect}:#{offset.inspect}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @param str [String] The string to move through.
|
|
27
|
+
# @return [Position] The source position after proceeding forward through
|
|
28
|
+
# `str`.
|
|
29
|
+
def after(str)
|
|
30
|
+
newlines = str.count("\n")
|
|
31
|
+
Position.new(line + newlines,
|
|
32
|
+
if newlines == 0
|
|
33
|
+
offset + str.length
|
|
34
|
+
else
|
|
35
|
+
str.length - str.rindex("\n") - 1
|
|
36
|
+
end)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Sass::Source
|
|
2
|
+
class Range
|
|
3
|
+
# The starting position of the range in the document (inclusive).
|
|
4
|
+
#
|
|
5
|
+
# @return [Sass::Source::Position]
|
|
6
|
+
attr_accessor :start_pos
|
|
7
|
+
|
|
8
|
+
# The ending position of the range in the document (exclusive).
|
|
9
|
+
#
|
|
10
|
+
# @return [Sass::Source::Position]
|
|
11
|
+
attr_accessor :end_pos
|
|
12
|
+
|
|
13
|
+
# The file in which this source range appears. This can be nil if the file
|
|
14
|
+
# is unknown or not yet generated.
|
|
15
|
+
#
|
|
16
|
+
# @return [String]
|
|
17
|
+
attr_accessor :file
|
|
18
|
+
|
|
19
|
+
# The importer that imported the file in which this source range appears.
|
|
20
|
+
# This is nil for target ranges.
|
|
21
|
+
#
|
|
22
|
+
# @return [Sass::Importers::Base]
|
|
23
|
+
attr_accessor :importer
|
|
24
|
+
|
|
25
|
+
# @param start_pos [Sass::Source::Position] See \{#start_pos}
|
|
26
|
+
# @param end_pos [Sass::Source::Position] See \{#end_pos}
|
|
27
|
+
# @param file [String] See \{#file}
|
|
28
|
+
# @param importer [Sass::Importers::Base] See \{#importer}
|
|
29
|
+
def initialize(start_pos, end_pos, file, importer = nil)
|
|
30
|
+
@start_pos = start_pos
|
|
31
|
+
@end_pos = end_pos
|
|
32
|
+
@file = file
|
|
33
|
+
@importer = importer
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String] A string representation of the source range.
|
|
37
|
+
def inspect
|
|
38
|
+
"(#{start_pos.inspect} to #{end_pos.inspect}#{" in #{@file}" if @file})"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/sass/stack.rb
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module Sass
|
|
2
|
+
# A class representing the stack when compiling a Sass file.
|
|
3
|
+
class Stack
|
|
4
|
+
# TODO: use this to generate stack information for Sass::SyntaxErrors.
|
|
5
|
+
|
|
6
|
+
# A single stack frame.
|
|
7
|
+
class Frame
|
|
8
|
+
# The filename of the file in which this stack frame was created.
|
|
9
|
+
#
|
|
10
|
+
# @return [String]
|
|
11
|
+
attr_reader :filename
|
|
12
|
+
|
|
13
|
+
# The line number on which this stack frame was created.
|
|
14
|
+
#
|
|
15
|
+
# @return [String]
|
|
16
|
+
attr_reader :line
|
|
17
|
+
|
|
18
|
+
# The type of this stack frame. This can be `:import`, `:mixin`, or
|
|
19
|
+
# `:base`.
|
|
20
|
+
#
|
|
21
|
+
# `:base` indicates that this is the bottom-most frame, meaning that it
|
|
22
|
+
# represents a single line of code rather than a nested context. The stack
|
|
23
|
+
# will only ever have one base frame, and it will always be the most
|
|
24
|
+
# deeply-nested frame.
|
|
25
|
+
#
|
|
26
|
+
# @return [Symbol?]
|
|
27
|
+
attr_reader :type
|
|
28
|
+
|
|
29
|
+
# The name of the stack frame. For mixin frames, this is the mixin name;
|
|
30
|
+
# otherwise, it's `nil`.
|
|
31
|
+
#
|
|
32
|
+
# @return [String?]
|
|
33
|
+
attr_reader :name
|
|
34
|
+
|
|
35
|
+
def initialize(filename, line, type, name = nil)
|
|
36
|
+
@filename = filename
|
|
37
|
+
@line = line
|
|
38
|
+
@type = type
|
|
39
|
+
@name = name
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Whether this frame represents an import.
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean]
|
|
45
|
+
def is_import?
|
|
46
|
+
type == :import
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Whether this frame represents a mixin.
|
|
50
|
+
#
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def is_mixin?
|
|
53
|
+
type == :mixin
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Whether this is the base frame.
|
|
57
|
+
#
|
|
58
|
+
# @return [Boolean]
|
|
59
|
+
def is_base?
|
|
60
|
+
type == :base
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The stack frames. The last frame is the most deeply-nested.
|
|
65
|
+
#
|
|
66
|
+
# @return [Array<Frame>]
|
|
67
|
+
attr_reader :frames
|
|
68
|
+
|
|
69
|
+
def initialize
|
|
70
|
+
@frames = []
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Pushes a base frame onto the stack.
|
|
74
|
+
#
|
|
75
|
+
# @param filename [String] See \{Frame#filename}.
|
|
76
|
+
# @param line [String] See \{Frame#line}.
|
|
77
|
+
# @yield [] A block in which the new frame is on the stack.
|
|
78
|
+
def with_base(filename, line)
|
|
79
|
+
with_frame(filename, line, :base) {yield}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Pushes an import frame onto the stack.
|
|
83
|
+
#
|
|
84
|
+
# @param filename [String] See \{Frame#filename}.
|
|
85
|
+
# @param line [String] See \{Frame#line}.
|
|
86
|
+
# @yield [] A block in which the new frame is on the stack.
|
|
87
|
+
def with_import(filename, line)
|
|
88
|
+
with_frame(filename, line, :import) {yield}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Pushes a mixin frame onto the stack.
|
|
92
|
+
#
|
|
93
|
+
# @param filename [String] See \{Frame#filename}.
|
|
94
|
+
# @param line [String] See \{Frame#line}.
|
|
95
|
+
# @param name [String] See \{Frame#name}.
|
|
96
|
+
# @yield [] A block in which the new frame is on the stack.
|
|
97
|
+
def with_mixin(filename, line, name)
|
|
98
|
+
with_frame(filename, line, :mixin, name) {yield}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def to_s
|
|
102
|
+
Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
|
|
103
|
+
map do |(frame, caller), i|
|
|
104
|
+
"#{i == 0 ? "on" : "from"} line #{frame.line}" +
|
|
105
|
+
" of #{frame.filename || "an unknown file"}" +
|
|
106
|
+
(caller && caller.name ? ", in `#{caller.name}'" : "")
|
|
107
|
+
end.join("\n")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def with_frame(filename, line, type, name = nil)
|
|
113
|
+
@frames.pop if @frames.last && @frames.last.type == :base
|
|
114
|
+
@frames.push(Frame.new(filename, line, type, name))
|
|
115
|
+
yield
|
|
116
|
+
ensure
|
|
117
|
+
@frames.pop unless type == :base && @frames.last && @frames.last.type != :base
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|