sass 3.3.0 → 3.4.25
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/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +76 -62
- data/Rakefile +104 -24
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +9 -5
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +12 -13
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +106 -70
- data/lib/sass/environment.rb +39 -19
- data/lib/sass/error.rb +17 -20
- data/lib/sass/exec/base.rb +199 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +440 -0
- data/lib/sass/exec.rb +5 -771
- data/lib/sass/features.rb +9 -2
- data/lib/sass/importers/base.rb +8 -3
- data/lib/sass/importers/filesystem.rb +30 -38
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/media.rb +1 -4
- data/lib/sass/plugin/compiler.rb +224 -90
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +4 -4
- data/lib/sass/plugin.rb +6 -5
- data/lib/sass/script/css_lexer.rb +1 -1
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +739 -318
- data/lib/sass/script/lexer.rb +134 -54
- data/lib/sass/script/parser.rb +252 -56
- data/lib/sass/script/tree/funcall.rb +13 -6
- data/lib/sass/script/tree/interpolation.rb +127 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +59 -38
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/value/base.rb +17 -14
- data/lib/sass/script/value/bool.rb +0 -5
- data/lib/sass/script/value/color.rb +78 -42
- data/lib/sass/script/value/helpers.rb +119 -2
- data/lib/sass/script/value/list.rb +0 -15
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/null.rb +0 -5
- data/lib/sass/script/value/number.rb +112 -31
- data/lib/sass/script/value/string.rb +102 -13
- data/lib/sass/script/value.rb +0 -1
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +24 -4
- data/lib/sass/scss/parser.rb +290 -383
- data/lib/sass/scss/rx.rb +17 -9
- data/lib/sass/scss/static_parser.rb +306 -4
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +35 -18
- data/lib/sass/selector/comma_sequence.rb +114 -19
- data/lib/sass/selector/pseudo.rb +266 -0
- data/lib/sass/selector/sequence.rb +146 -40
- data/lib/sass/selector/simple.rb +22 -33
- data/lib/sass/selector/simple_sequence.rb +122 -39
- data/lib/sass/selector.rb +57 -197
- data/lib/sass/shared.rb +2 -2
- data/lib/sass/source/map.rb +31 -14
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -8
- data/lib/sass/supports.rb +10 -13
- data/lib/sass/tree/at_root_node.rb +1 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -1
- data/lib/sass/tree/directive_node.rb +8 -2
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +1 -1
- data/lib/sass/tree/function_node.rb +9 -0
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +6 -7
- data/lib/sass/tree/rule_node.rb +26 -11
- data/lib/sass/tree/visitors/check_nesting.rb +56 -32
- data/lib/sass/tree/visitors/convert.rb +59 -44
- data/lib/sass/tree/visitors/cssize.rb +34 -30
- data/lib/sass/tree/visitors/deep_copy.rb +6 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +87 -50
- data/lib/sass/tree/visitors/set_options.rb +15 -1
- data/lib/sass/tree/visitors/to_css.rb +72 -43
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +2 -3
- data/lib/sass/util.rb +334 -154
- data/lib/sass/version.rb +7 -7
- data/lib/sass.rb +10 -8
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +24 -11
- data/test/sass/conversion_test.rb +241 -50
- data/test/sass/css2sass_test.rb +73 -5
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +343 -260
- data/test/sass/exec_test.rb +12 -2
- data/test/sass/extend_test.rb +333 -44
- data/test/sass/functions_test.rb +353 -260
- data/test/sass/importer_test.rb +40 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +24 -21
- 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 +5 -5
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +71 -39
- data/test/sass/script_test.rb +714 -123
- data/test/sass/scss/css_test.rb +213 -30
- data/test/sass/scss/rx_test.rb +8 -4
- data/test/sass/scss/scss_test.rb +766 -22
- data/test/sass/source_map_test.rb +263 -95
- data/test/sass/superselector_test.rb +210 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
- data/test/sass/util/normalized_map_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +46 -45
- data/test/sass/value_helpers_test.rb +5 -7
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +7 -6
- data/vendor/listen/CHANGELOG.md +1 -228
- data/vendor/listen/Gemfile +5 -15
- data/vendor/listen/README.md +111 -77
- data/vendor/listen/Rakefile +0 -42
- data/vendor/listen/lib/listen/adapter.rb +195 -82
- data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
- data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
- data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
- data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
- data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
- data/vendor/listen/lib/listen/directory_record.rb +96 -61
- data/vendor/listen/lib/listen/listener.rb +135 -37
- data/vendor/listen/lib/listen/turnstile.rb +9 -5
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/lib/listen.rb +33 -19
- data/vendor/listen/listen.gemspec +6 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
- data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
- data/vendor/listen/spec/listen/listener_spec.rb +128 -39
- data/vendor/listen/spec/listen_spec.rb +15 -21
- data/vendor/listen/spec/spec_helper.rb +4 -0
- data/vendor/listen/spec/support/adapter_helper.rb +52 -15
- data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
- data/vendor/listen/spec/support/listeners_helper.rb +30 -7
- metadata +310 -300
- data/CONTRIBUTING +0 -3
- data/ext/mkrf_conf.rb +0 -27
- data/lib/sass/script/value/deprecated_false.rb +0 -55
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -26,11 +26,10 @@ module Sass
|
|
26
26
|
|
27
27
|
# @see Base#retrieve
|
28
28
|
def retrieve(key, sha)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
29
|
+
return unless @contents.has_key?(key)
|
30
|
+
return unless @contents[key][:sha] == sha
|
31
|
+
obj = @contents[key][:obj]
|
32
|
+
obj.respond_to?(:deep_copy) ? obj.deep_copy : obj.dup
|
34
33
|
end
|
35
34
|
|
36
35
|
# @see Base#store
|
data/lib/sass/callbacks.rb
CHANGED
@@ -51,12 +51,12 @@ module Sass
|
|
51
51
|
def define_callback(name)
|
52
52
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
53
53
|
def on_#{name}(&block)
|
54
|
-
@_sass_callbacks
|
54
|
+
@_sass_callbacks = {} unless defined? @_sass_callbacks
|
55
55
|
(@_sass_callbacks[#{name.inspect}] ||= []) << block
|
56
56
|
end
|
57
57
|
|
58
58
|
def run_#{name}(*args)
|
59
|
-
return unless @_sass_callbacks
|
59
|
+
return unless defined? @_sass_callbacks
|
60
60
|
return unless @_sass_callbacks[#{name.inspect}]
|
61
61
|
@_sass_callbacks[#{name.inspect}].each {|c| c[*args]}
|
62
62
|
end
|
data/lib/sass/css.rb
CHANGED
@@ -18,7 +18,7 @@ module Sass
|
|
18
18
|
# that can be converted to Unicode.
|
19
19
|
# If the stylesheet contains an `@charset` declaration,
|
20
20
|
# that overrides the Ruby encoding
|
21
|
-
# (see {file:SASS_REFERENCE.md#
|
21
|
+
# (see {file:SASS_REFERENCE.md#Encodings the encoding documentation})
|
22
22
|
# @option options :old [Boolean] (false)
|
23
23
|
# Whether or not to output old property syntax
|
24
24
|
# (`:color blue` as opposed to `color: blue`).
|
@@ -31,10 +31,11 @@ module Sass
|
|
31
31
|
template = template.read
|
32
32
|
end
|
33
33
|
|
34
|
-
@options = options.
|
34
|
+
@options = options.merge(:_convert => true)
|
35
35
|
# Backwards compatibility
|
36
36
|
@options[:old] = true if @options[:alternate] == false
|
37
37
|
@template = template
|
38
|
+
@checked_encoding = false
|
38
39
|
end
|
39
40
|
|
40
41
|
# Converts the CSS template into Sass or SCSS code.
|
@@ -67,9 +68,7 @@ module Sass
|
|
67
68
|
def check_encoding!
|
68
69
|
return if @checked_encoding
|
69
70
|
@checked_encoding = true
|
70
|
-
@template, @original_encoding = Sass::Util.check_sass_encoding(@template)
|
71
|
-
raise Sass::SyntaxError.new(msg, :line => line)
|
72
|
-
end
|
71
|
+
@template, @original_encoding = Sass::Util.check_sass_encoding(@template)
|
73
72
|
end
|
74
73
|
|
75
74
|
# Parses the CSS template and applies various transformations
|
@@ -77,14 +76,14 @@ module Sass
|
|
77
76
|
# @return [Tree::Node] The root node of the parsed tree
|
78
77
|
def build_tree
|
79
78
|
root = Sass::SCSS::CssParser.new(@template, @options[:filename], nil).parse
|
80
|
-
parse_selectors
|
81
|
-
expand_commas
|
82
|
-
nest_seqs
|
83
|
-
parent_ref_rules
|
84
|
-
flatten_rules
|
85
|
-
bubble_subject
|
86
|
-
fold_commas
|
87
|
-
dump_selectors
|
79
|
+
parse_selectors(root)
|
80
|
+
expand_commas(root)
|
81
|
+
nest_seqs(root)
|
82
|
+
parent_ref_rules(root)
|
83
|
+
flatten_rules(root)
|
84
|
+
bubble_subject(root)
|
85
|
+
fold_commas(root)
|
86
|
+
dump_selectors(root)
|
88
87
|
root
|
89
88
|
end
|
90
89
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Sass
|
2
|
+
# A deprecation warning that should only be printed once for a given line in a
|
3
|
+
# given file.
|
4
|
+
#
|
5
|
+
# A global Deprecation instance should be created for each type of deprecation
|
6
|
+
# warning, and `warn` should be called each time a warning is needed.
|
7
|
+
class Deprecation
|
8
|
+
@@allow_double_warnings = false
|
9
|
+
|
10
|
+
# Runs a block in which double deprecation warnings for the same location
|
11
|
+
# are allowed.
|
12
|
+
def self.allow_double_warnings
|
13
|
+
old_allow_double_warnings = @@allow_double_warnings
|
14
|
+
@@allow_double_warnings = true
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
@@allow_double_warnings = old_allow_double_warnings
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
# A set of filename, line pairs for which warnings have been emitted.
|
22
|
+
@seen = Set.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Prints `message` as a deprecation warning associated with `filename`,
|
26
|
+
# `line`, and optionally `column`.
|
27
|
+
#
|
28
|
+
# This ensures that only one message will be printed for each line of a
|
29
|
+
# given file.
|
30
|
+
#
|
31
|
+
# @overload warn(filename, line, message)
|
32
|
+
# @param filename [String, nil]
|
33
|
+
# @param line [Number]
|
34
|
+
# @param message [String]
|
35
|
+
# @overload warn(filename, line, column, message)
|
36
|
+
# @param filename [String, nil]
|
37
|
+
# @param line [Number]
|
38
|
+
# @param column [Number]
|
39
|
+
# @param message [String]
|
40
|
+
def warn(filename, line, column_or_message, message = nil)
|
41
|
+
return if !@@allow_double_warnings && @seen.add?([filename, line]).nil?
|
42
|
+
if message
|
43
|
+
column = column_or_message
|
44
|
+
else
|
45
|
+
message = column_or_message
|
46
|
+
end
|
47
|
+
|
48
|
+
location = "line #{line}"
|
49
|
+
location << ", column #{column}" if column
|
50
|
+
location << " of #{filename}" if filename
|
51
|
+
|
52
|
+
Sass::Util.sass_warn("DEPRECATION WARNING on #{location}:\n#{message}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/sass/engine.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'sass/cache_stores'
|
4
|
+
require 'sass/deprecation'
|
4
5
|
require 'sass/source/position'
|
5
6
|
require 'sass/source/range'
|
6
7
|
require 'sass/source/map'
|
@@ -30,6 +31,8 @@ require 'sass/tree/warn_node'
|
|
30
31
|
require 'sass/tree/import_node'
|
31
32
|
require 'sass/tree/charset_node'
|
32
33
|
require 'sass/tree/at_root_node'
|
34
|
+
require 'sass/tree/keyframe_rule_node'
|
35
|
+
require 'sass/tree/error_node'
|
33
36
|
require 'sass/tree/visitors/base'
|
34
37
|
require 'sass/tree/visitors/perform'
|
35
38
|
require 'sass/tree/visitors/cssize'
|
@@ -82,23 +85,25 @@ module Sass
|
|
82
85
|
# This class handles the parsing and compilation of the Sass template.
|
83
86
|
# Example usage:
|
84
87
|
#
|
85
|
-
# template = File.
|
88
|
+
# template = File.read('stylesheets/sassy.sass')
|
86
89
|
# sass_engine = Sass::Engine.new(template)
|
87
90
|
# output = sass_engine.render
|
88
91
|
# puts output
|
89
92
|
class Engine
|
93
|
+
@@old_property_deprecation = Deprecation.new
|
94
|
+
|
90
95
|
# A line of Sass code.
|
91
96
|
#
|
92
97
|
# `text`: `String`
|
93
98
|
# : The text in the line, without any whitespace at the beginning or end.
|
94
99
|
#
|
95
|
-
# `tabs`: `
|
100
|
+
# `tabs`: `Integer`
|
96
101
|
# : The level of indentation of the line.
|
97
102
|
#
|
98
|
-
# `index`: `
|
103
|
+
# `index`: `Integer`
|
99
104
|
# : The line number in the original document.
|
100
105
|
#
|
101
|
-
# `offset`: `
|
106
|
+
# `offset`: `Integer`
|
102
107
|
# : The number of bytes in on the line that the text begins.
|
103
108
|
# This ends up being the number of bytes of leading whitespace.
|
104
109
|
#
|
@@ -155,7 +160,7 @@ module Sass
|
|
155
160
|
# @api public
|
156
161
|
DEFAULT_OPTIONS = {
|
157
162
|
:style => :nested,
|
158
|
-
:load_paths => [
|
163
|
+
:load_paths => [],
|
159
164
|
:cache => true,
|
160
165
|
:cache_location => './.sass-cache',
|
161
166
|
:syntax => :sass,
|
@@ -166,11 +171,11 @@ module Sass
|
|
166
171
|
# default values and resolving aliases.
|
167
172
|
#
|
168
173
|
# @param options [{Symbol => Object}] The options hash;
|
169
|
-
# see {file:SASS_REFERENCE.md#
|
174
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
170
175
|
# @return [{Symbol => Object}] The normalized options hash.
|
171
176
|
# @private
|
172
177
|
def self.normalize_options(options)
|
173
|
-
options = DEFAULT_OPTIONS.merge(options.reject {|
|
178
|
+
options = DEFAULT_OPTIONS.merge(options.reject {|_k, v| v.nil?})
|
174
179
|
|
175
180
|
# If the `:filename` option is passed in without an importer,
|
176
181
|
# assume it's using the default filesystem importer.
|
@@ -206,6 +211,8 @@ module Sass
|
|
206
211
|
when :alternate; options[:property_syntax] = :new
|
207
212
|
when :normal; options[:property_syntax] = :old
|
208
213
|
end
|
214
|
+
options[:sourcemap] = :auto if options[:sourcemap] == true
|
215
|
+
options[:sourcemap] = :none if options[:sourcemap] == false
|
209
216
|
|
210
217
|
options
|
211
218
|
end
|
@@ -218,14 +225,14 @@ module Sass
|
|
218
225
|
#
|
219
226
|
# @param filename [String] The path to the Sass or SCSS file
|
220
227
|
# @param options [{Symbol => Object}] The options hash;
|
221
|
-
# See {file:SASS_REFERENCE.md#
|
228
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
222
229
|
# @return [Sass::Engine] The Engine for the given Sass or SCSS file.
|
223
230
|
# @raise [Sass::SyntaxError] if there's an error in the document.
|
224
231
|
def self.for_file(filename, options)
|
225
232
|
had_syntax = options[:syntax]
|
226
233
|
|
227
234
|
if had_syntax
|
228
|
-
# Use what was explicitly
|
235
|
+
# Use what was explicitly specified
|
229
236
|
elsif filename =~ /\.scss$/
|
230
237
|
options.merge!(:syntax => :scss)
|
231
238
|
elsif filename =~ /\.sass$/
|
@@ -236,7 +243,7 @@ module Sass
|
|
236
243
|
end
|
237
244
|
|
238
245
|
# The options for the Sass engine.
|
239
|
-
# See {file:SASS_REFERENCE.md#
|
246
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
240
247
|
#
|
241
248
|
# @return [{Symbol => Object}]
|
242
249
|
attr_reader :options
|
@@ -253,14 +260,17 @@ module Sass
|
|
253
260
|
# that can be converted to Unicode.
|
254
261
|
# If the template contains an `@charset` declaration,
|
255
262
|
# that overrides the Ruby encoding
|
256
|
-
# (see {file:SASS_REFERENCE.md#
|
263
|
+
# (see {file:SASS_REFERENCE.md#Encodings the encoding documentation})
|
257
264
|
# @param options [{Symbol => Object}] An options hash.
|
258
|
-
# See {file:SASS_REFERENCE.md#
|
265
|
+
# See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
259
266
|
# @see {Sass::Engine.for_file}
|
260
267
|
# @see {Sass::Plugin}
|
261
268
|
def initialize(template, options = {})
|
262
269
|
@options = self.class.normalize_options(options)
|
263
270
|
@template = template
|
271
|
+
@checked_encoding = false
|
272
|
+
@filename = nil
|
273
|
+
@line = nil
|
264
274
|
end
|
265
275
|
|
266
276
|
# Render the template to CSS.
|
@@ -271,8 +281,8 @@ module Sass
|
|
271
281
|
# cannot be converted to UTF-8
|
272
282
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
273
283
|
def render
|
274
|
-
return
|
275
|
-
Sass::Util.silence_sass_warnings {
|
284
|
+
return _to_tree.render unless @options[:quiet]
|
285
|
+
Sass::Util.silence_sass_warnings {_to_tree.render}
|
276
286
|
end
|
277
287
|
|
278
288
|
# Render the template to CSS and return the source map.
|
@@ -315,7 +325,7 @@ module Sass
|
|
315
325
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
316
326
|
def source_encoding
|
317
327
|
check_encoding!
|
318
|
-
@
|
328
|
+
@source_encoding
|
319
329
|
end
|
320
330
|
|
321
331
|
# Gets a set of all the documents
|
@@ -360,7 +370,10 @@ Error generating source map: couldn't determine public URL for "#{filename}".
|
|
360
370
|
Without a public URL, there's nothing for the source map to link to.
|
361
371
|
An importer was not set for this file.
|
362
372
|
ERR
|
363
|
-
elsif Sass::Util.silence_warnings
|
373
|
+
elsif Sass::Util.silence_warnings do
|
374
|
+
sourcemap_dir = nil if @options[:sourcemap] == :file
|
375
|
+
importer.public_url(filename, sourcemap_dir).nil?
|
376
|
+
end
|
364
377
|
raise Sass::SyntaxError.new(<<ERR)
|
365
378
|
Error generating source map: couldn't determine public URL for "#{filename}".
|
366
379
|
Without a public URL, there's nothing for the source map to link to.
|
@@ -375,23 +388,12 @@ ERR
|
|
375
388
|
rendered << "/*# sourceMappingURL="
|
376
389
|
rendered << Sass::Util.escape_uri(sourcemap_uri)
|
377
390
|
rendered << " */\n"
|
378
|
-
rendered = encode_and_set_charset(rendered)
|
379
391
|
return rendered, sourcemap
|
380
392
|
end
|
381
393
|
|
382
|
-
def encode_and_set_charset(rendered)
|
383
|
-
return rendered if Sass::Util.ruby1_8?
|
384
|
-
begin
|
385
|
-
# Try to convert the result to the original encoding,
|
386
|
-
# but if that doesn't work fall back on UTF-8
|
387
|
-
rendered = rendered.encode(source_encoding)
|
388
|
-
rescue EncodingError
|
389
|
-
end
|
390
|
-
rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
|
391
|
-
"@charset \"#{source_encoding.name}\"".encode(source_encoding))
|
392
|
-
end
|
393
|
-
|
394
394
|
def _to_tree
|
395
|
+
check_encoding!
|
396
|
+
|
395
397
|
if (@options[:cache] || @options[:read_cache]) &&
|
396
398
|
@options[:filename] && @options[:importer]
|
397
399
|
key = sassc_key
|
@@ -403,8 +405,6 @@ ERR
|
|
403
405
|
end
|
404
406
|
end
|
405
407
|
|
406
|
-
check_encoding!
|
407
|
-
|
408
408
|
if @options[:syntax] == :scss
|
409
409
|
root = Sass::SCSS::Parser.new(@template, @options[:filename], @options[:importer]).parse
|
410
410
|
else
|
@@ -436,9 +436,7 @@ ERR
|
|
436
436
|
def check_encoding!
|
437
437
|
return if @checked_encoding
|
438
438
|
@checked_encoding = true
|
439
|
-
@template, @
|
440
|
-
raise Sass::SyntaxError.new(msg, :line => line)
|
441
|
-
end
|
439
|
+
@template, @source_encoding = Sass::Util.check_sass_encoding(@template)
|
442
440
|
end
|
443
441
|
|
444
442
|
def tabulate(string)
|
@@ -446,7 +444,7 @@ ERR
|
|
446
444
|
comment_tab_str = nil
|
447
445
|
first = true
|
448
446
|
lines = []
|
449
|
-
string.
|
447
|
+
string.scan(/^[^\n]*?$/).each_with_index do |line, index|
|
450
448
|
index += (@options[:line] || 1)
|
451
449
|
if line.strip.empty?
|
452
450
|
lines.last.text << "\n" if lines.last && lines.last.comment?
|
@@ -484,7 +482,7 @@ ERR
|
|
484
482
|
|
485
483
|
line_tabs = line_tab_str.scan(tab_str).size
|
486
484
|
if tab_str * line_tabs != line_tab_str
|
487
|
-
message = <<END.strip.
|
485
|
+
message = <<END.strip.tr("\n", ' ')
|
488
486
|
Inconsistent indentation: #{Sass::Shared.human_indentation line_tab_str, true} used for indentation,
|
489
487
|
but the rest of the document was indented using #{Sass::Shared.human_indentation tab_str}.
|
490
488
|
END
|
@@ -497,15 +495,13 @@ END
|
|
497
495
|
end
|
498
496
|
|
499
497
|
# @comment
|
500
|
-
# rubocop:disable ParameterLists
|
501
498
|
def try_comment(line, last, tab_str, comment_tab_str, index)
|
502
|
-
# rubocop:enable ParameterLists
|
503
499
|
return unless last && last.comment?
|
504
500
|
# Nested comment stuff must be at least one whitespace char deeper
|
505
501
|
# than the normal indentation
|
506
502
|
return unless line =~ /^#{tab_str}\s/
|
507
503
|
unless line =~ /^(?:#{comment_tab_str})(.*)$/
|
508
|
-
raise SyntaxError.new(<<MSG.strip.
|
504
|
+
raise SyntaxError.new(<<MSG.strip.tr("\n", " "), :line => index)
|
509
505
|
Inconsistent indentation:
|
510
506
|
previous line was indented by #{Sass::Shared.human_indentation comment_tab_str},
|
511
507
|
but this line was indented by #{Sass::Shared.human_indentation line[/^\s*/]}.
|
@@ -582,8 +578,8 @@ MSG
|
|
582
578
|
if continued_comment &&
|
583
579
|
child.line == continued_comment.line +
|
584
580
|
continued_comment.lines + 1
|
585
|
-
continued_comment.value.last.sub!(
|
586
|
-
child.value.first.gsub!(
|
581
|
+
continued_comment.value.last.sub!(%r{ \*/\Z}, '')
|
582
|
+
child.value.first.gsub!(%r{\A/\*}, ' *')
|
587
583
|
continued_comment.value += ["\n"] + child.value
|
588
584
|
next
|
589
585
|
end
|
@@ -632,6 +628,11 @@ WARNING
|
|
632
628
|
raise SyntaxError.new("Invalid property: \"#{line.text}\".",
|
633
629
|
:line => @line) if name.nil? || value.nil?
|
634
630
|
|
631
|
+
@@old_property_deprecation.warn(@options[:filename], @line, <<WARNING)
|
632
|
+
Old-style properties like "#{line.text}" are deprecated and will be an error in future versions of Sass.
|
633
|
+
Use "#{name}: #{value}" instead.
|
634
|
+
WARNING
|
635
|
+
|
635
636
|
value_start_offset = name_end_offset = name_start_offset + name.length
|
636
637
|
unless value.empty?
|
637
638
|
# +1 and -1 both compensate for the leading ':', which is part of line.text
|
@@ -725,9 +726,12 @@ WARNING
|
|
725
726
|
expr = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
726
727
|
end_offset = start_offset
|
727
728
|
else
|
728
|
-
expr = parse_script(value,
|
729
|
+
expr = parse_script(value,
|
730
|
+
:offset => to_parser_offset(start_offset),
|
731
|
+
:css_variable => name.start_with?("--"))
|
729
732
|
end_offset = expr.source_range.end_pos.offset - 1
|
730
733
|
end
|
734
|
+
|
731
735
|
node = Tree::PropNode.new(parse_interp(name), expr, prop)
|
732
736
|
node.value_source_range = Sass::Source::Range.new(
|
733
737
|
Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
|
@@ -784,7 +788,19 @@ WARNING
|
|
784
788
|
else
|
785
789
|
:normal
|
786
790
|
end
|
787
|
-
Tree::CommentNode.new(value, type)
|
791
|
+
comment = Tree::CommentNode.new(value, type)
|
792
|
+
comment.line = line.index
|
793
|
+
text = line.text.rstrip
|
794
|
+
if text.include?("\n")
|
795
|
+
end_offset = text.length - text.rindex("\n")
|
796
|
+
else
|
797
|
+
end_offset = to_parser_offset(line.offset + text.length)
|
798
|
+
end
|
799
|
+
comment.source_range = Sass::Source::Range.new(
|
800
|
+
Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
|
801
|
+
Sass::Source::Position.new(@line + text.count("\n"), end_offset),
|
802
|
+
@options[:filename])
|
803
|
+
comment
|
788
804
|
else
|
789
805
|
Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
|
790
806
|
end
|
@@ -792,16 +808,14 @@ WARNING
|
|
792
808
|
|
793
809
|
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
794
810
|
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
795
|
-
:at_root]
|
811
|
+
:at_root, :error]
|
796
812
|
|
797
|
-
# @comment
|
798
|
-
# rubocop:disable MethodLength
|
799
813
|
def parse_directive(parent, line, root)
|
800
814
|
directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
|
801
815
|
raise SyntaxError.new("Invalid directive: '@'.") unless directive
|
802
816
|
offset = directive.size + whitespace.size + 1 if whitespace
|
803
817
|
|
804
|
-
directive_name = directive.
|
818
|
+
directive_name = directive.tr('-', '_').to_sym
|
805
819
|
if DIRECTIVES.include?(directive_name)
|
806
820
|
return send("parse_#{directive_name}_directive", parent, line, root, value, offset)
|
807
821
|
end
|
@@ -834,6 +848,14 @@ WARNING
|
|
834
848
|
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
835
849
|
end
|
836
850
|
|
851
|
+
def parse_error_directive(parent, line, root, value, offset)
|
852
|
+
raise SyntaxError.new("Invalid error directive '@error': expected expression.") unless value
|
853
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath error directives.",
|
854
|
+
:line => @line + 1) unless line.children.empty?
|
855
|
+
offset = line.offset + line.text.index(value).to_i
|
856
|
+
Tree::ErrorNode.new(parse_script(value, :offset => offset))
|
857
|
+
end
|
858
|
+
|
837
859
|
def parse_extend_directive(parent, line, root, value, offset)
|
838
860
|
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
839
861
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
@@ -848,8 +870,6 @@ WARNING
|
|
848
870
|
)
|
849
871
|
Tree::ExtendNode.new(interp_parsed, optional, selector_range)
|
850
872
|
end
|
851
|
-
# @comment
|
852
|
-
# rubocop:enable MethodLength
|
853
873
|
|
854
874
|
def parse_warn_directive(parent, line, root, value, offset)
|
855
875
|
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
@@ -1009,15 +1029,25 @@ WARNING
|
|
1009
1029
|
script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
|
1010
1030
|
str = script_parser.parse_string
|
1011
1031
|
|
1012
|
-
|
1013
|
-
@options[:filename], @options[:importer],
|
1014
|
-
@line, str.source_range.end_pos.offset)
|
1015
|
-
if (media = media_parser.parse_media_query_list)
|
1016
|
-
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
1017
|
-
node = Tree::CssImportNode.new(str, media.to_a)
|
1018
|
-
else
|
1032
|
+
if scanner.eos?
|
1019
1033
|
end_pos = str.source_range.end_pos
|
1020
1034
|
node = Tree::CssImportNode.new(str)
|
1035
|
+
else
|
1036
|
+
supports_parser = Sass::SCSS::Parser.new(scanner,
|
1037
|
+
@options[:filename], @options[:importer],
|
1038
|
+
@line, str.source_range.end_pos.offset)
|
1039
|
+
supports_condition = supports_parser.parse_supports_clause
|
1040
|
+
|
1041
|
+
if scanner.eos?
|
1042
|
+
node = Tree::CssImportNode.new(str, [], supports_condition)
|
1043
|
+
else
|
1044
|
+
media_parser = Sass::SCSS::Parser.new(scanner,
|
1045
|
+
@options[:filename], @options[:importer],
|
1046
|
+
@line, str.source_range.end_pos.offset)
|
1047
|
+
media = media_parser.parse_media_query_list
|
1048
|
+
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
1049
|
+
node = Tree::CssImportNode.new(str, media.to_a, supports_condition)
|
1050
|
+
end
|
1021
1051
|
end
|
1022
1052
|
|
1023
1053
|
node.source_range = Sass::Source::Range.new(
|
@@ -1026,7 +1056,7 @@ WARNING
|
|
1026
1056
|
return node
|
1027
1057
|
end
|
1028
1058
|
|
1029
|
-
unless (
|
1059
|
+
unless (quoted_val = scanner.scan(Sass::SCSS::RX::STRING))
|
1030
1060
|
scanned = scanner.scan(/[^,;]+/)
|
1031
1061
|
node = Tree::ImportNode.new(scanned)
|
1032
1062
|
start_parser_offset = to_parser_offset(offset)
|
@@ -1038,21 +1068,21 @@ WARNING
|
|
1038
1068
|
end
|
1039
1069
|
|
1040
1070
|
start_offset = offset
|
1041
|
-
offset +=
|
1042
|
-
val = scanner[1] || scanner[2]
|
1071
|
+
offset += scanner.matched.length
|
1072
|
+
val = Sass::Script::Value::String.value(scanner[1] || scanner[2])
|
1043
1073
|
scanned = scanner.scan(/\s*/)
|
1044
1074
|
if !scanner.match?(/[,;]|$/)
|
1045
1075
|
offset += scanned.length if scanned
|
1046
1076
|
media_parser = Sass::SCSS::Parser.new(scanner,
|
1047
1077
|
@options[:filename], @options[:importer], @line, offset)
|
1048
1078
|
media = media_parser.parse_media_query_list
|
1049
|
-
node = Tree::CssImportNode.new(
|
1079
|
+
node = Tree::CssImportNode.new(quoted_val, media.to_a)
|
1050
1080
|
node.source_range = Sass::Source::Range.new(
|
1051
1081
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1052
1082
|
Sass::Source::Position.new(@line, media_parser.offset),
|
1053
1083
|
@options[:filename], @options[:importer])
|
1054
1084
|
elsif val =~ %r{^(https?:)?//}
|
1055
|
-
node = Tree::CssImportNode.new(
|
1085
|
+
node = Tree::CssImportNode.new(quoted_val)
|
1056
1086
|
node.source_range = Sass::Source::Range.new(
|
1057
1087
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1058
1088
|
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
@@ -1124,9 +1154,9 @@ WARNING
|
|
1124
1154
|
end
|
1125
1155
|
|
1126
1156
|
def parse_script(script, options = {})
|
1127
|
-
line = options
|
1128
|
-
offset = options
|
1129
|
-
Script.parse(script, line, offset, @options)
|
1157
|
+
line = options.delete(:line) || @line
|
1158
|
+
offset = options.delete(:offset) || @offset + 1
|
1159
|
+
Script.parse(script, line, offset, @options.merge(options))
|
1130
1160
|
end
|
1131
1161
|
|
1132
1162
|
def format_comment_text(text, silent)
|
@@ -1138,9 +1168,10 @@ WARNING
|
|
1138
1168
|
end
|
1139
1169
|
|
1140
1170
|
return "/* */" if content.empty?
|
1141
|
-
content.last.gsub!(
|
1171
|
+
content.last.gsub!(%r{ ?\*/ *$}, '')
|
1172
|
+
first = content.shift unless removed_first
|
1142
1173
|
content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
|
1143
|
-
content.first
|
1174
|
+
content.unshift first unless removed_first
|
1144
1175
|
if silent
|
1145
1176
|
"/*" + content.join("\n *") + " */"
|
1146
1177
|
else
|
@@ -1178,10 +1209,15 @@ WARNING
|
|
1178
1209
|
res << "\\" * (escapes - 1) << '#{'
|
1179
1210
|
else
|
1180
1211
|
res << "\\" * [0, escapes - 1].max
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1212
|
+
if scan[1].include?("\n")
|
1213
|
+
line += scan[1].count("\n")
|
1214
|
+
offset = scan.matched_size - scan[1].rindex("\n")
|
1215
|
+
else
|
1216
|
+
offset += scan.matched_size
|
1217
|
+
end
|
1218
|
+
node = Script::Parser.new(scan, line, offset, options).parse_interpolated
|
1219
|
+
offset = node.source_range.end_pos.offset
|
1220
|
+
res << node
|
1185
1221
|
end
|
1186
1222
|
end
|
1187
1223
|
res << rest
|
data/lib/sass/environment.rb
CHANGED
@@ -41,7 +41,7 @@ module Sass
|
|
41
41
|
if @#{name}s.include?(name)
|
42
42
|
@#{name}s[name] = value
|
43
43
|
true
|
44
|
-
elsif @parent
|
44
|
+
elsif @parent && !@parent.global?
|
45
45
|
@parent.try_set_#{name}(name, value)
|
46
46
|
else
|
47
47
|
false
|
@@ -53,6 +53,10 @@ module Sass
|
|
53
53
|
@#{name}s ||= {}
|
54
54
|
@#{name}s[name.tr('_', '-')] = value
|
55
55
|
end
|
56
|
+
|
57
|
+
def set_global_#{name}(name, value)
|
58
|
+
global_env.set_#{name}(name, value)
|
59
|
+
end
|
56
60
|
RUBY
|
57
61
|
end
|
58
62
|
end
|
@@ -76,28 +80,27 @@ module Sass
|
|
76
80
|
# Sass::Callable
|
77
81
|
inherited_hash_reader :function
|
78
82
|
|
79
|
-
# Whether a warning has been emitted for assigning to the given
|
80
|
-
# global variable. This is a set of tuples containing the name of
|
81
|
-
# the variable, its filename, and its line number.
|
82
|
-
#
|
83
|
-
# @return [Set<[String, String, int]>]
|
84
|
-
attr_reader :global_warning_given
|
85
|
-
|
86
|
-
# Whether a warning has been emitted for misusing a deprecated false value.
|
87
|
-
# This is a set of tuples containing the filename and its line number.
|
88
|
-
#
|
89
|
-
# @return [Set<[String, int]>]
|
90
|
-
attr_reader :deprecated_false_warning_given
|
91
|
-
|
92
83
|
# @param options [{Symbol => Object}] The options hash. See
|
93
|
-
# {file:SASS_REFERENCE.md#
|
84
|
+
# {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
94
85
|
# @param parent [Environment] See \{#parent}
|
95
86
|
def initialize(parent = nil, options = nil)
|
96
87
|
@parent = parent
|
97
88
|
@options = options || (parent && parent.options) || {}
|
98
|
-
@stack = Sass::Stack.new
|
99
|
-
@
|
100
|
-
@
|
89
|
+
@stack = @parent.nil? ? Sass::Stack.new : nil
|
90
|
+
@caller = nil
|
91
|
+
@content = nil
|
92
|
+
@filename = nil
|
93
|
+
@functions = nil
|
94
|
+
@mixins = nil
|
95
|
+
@selector = nil
|
96
|
+
@vars = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns whether this is the global environment.
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
def global?
|
103
|
+
@parent.nil?
|
101
104
|
end
|
102
105
|
|
103
106
|
# The environment of the caller of this environment's mixin or function.
|
@@ -128,7 +131,7 @@ module Sass
|
|
128
131
|
#
|
129
132
|
# @return [Environment]
|
130
133
|
def global_env
|
131
|
-
@global_env ||=
|
134
|
+
@global_env ||= global? ? self : @parent.global_env
|
132
135
|
end
|
133
136
|
|
134
137
|
# The import/mixin stack.
|
@@ -192,4 +195,21 @@ module Sass
|
|
192
195
|
@content ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
|
193
196
|
end
|
194
197
|
end
|
198
|
+
|
199
|
+
# An environment that can write to in-scope global variables, but doesn't
|
200
|
+
# create new variables in the global scope. Useful for top-level control
|
201
|
+
# directives.
|
202
|
+
class SemiGlobalEnvironment < Environment
|
203
|
+
def try_set_var(name, value)
|
204
|
+
@vars ||= {}
|
205
|
+
if @vars.include?(name)
|
206
|
+
@vars[name] = value
|
207
|
+
true
|
208
|
+
elsif @parent
|
209
|
+
@parent.try_set_var(name, value)
|
210
|
+
else
|
211
|
+
false
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
195
215
|
end
|