sass4 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/AGENTS.md +534 -0
  4. data/CODE_OF_CONDUCT.md +10 -0
  5. data/CONTRIBUTING.md +148 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +242 -0
  8. data/VERSION +1 -0
  9. data/VERSION_NAME +1 -0
  10. data/bin/sass +13 -0
  11. data/bin/sass-convert +12 -0
  12. data/bin/scss +13 -0
  13. data/extra/sass-spec-ref.sh +40 -0
  14. data/extra/update_watch.rb +13 -0
  15. data/init.rb +18 -0
  16. data/lib/sass/cache_stores/base.rb +88 -0
  17. data/lib/sass/cache_stores/chain.rb +34 -0
  18. data/lib/sass/cache_stores/filesystem.rb +60 -0
  19. data/lib/sass/cache_stores/memory.rb +46 -0
  20. data/lib/sass/cache_stores/null.rb +25 -0
  21. data/lib/sass/cache_stores.rb +15 -0
  22. data/lib/sass/callbacks.rb +67 -0
  23. data/lib/sass/css.rb +407 -0
  24. data/lib/sass/deprecation.rb +55 -0
  25. data/lib/sass/engine.rb +1236 -0
  26. data/lib/sass/environment.rb +236 -0
  27. data/lib/sass/error.rb +198 -0
  28. data/lib/sass/exec/base.rb +188 -0
  29. data/lib/sass/exec/sass_convert.rb +283 -0
  30. data/lib/sass/exec/sass_scss.rb +436 -0
  31. data/lib/sass/exec.rb +9 -0
  32. data/lib/sass/features.rb +48 -0
  33. data/lib/sass/importers/base.rb +182 -0
  34. data/lib/sass/importers/deprecated_path.rb +51 -0
  35. data/lib/sass/importers/filesystem.rb +221 -0
  36. data/lib/sass/importers.rb +23 -0
  37. data/lib/sass/logger/base.rb +47 -0
  38. data/lib/sass/logger/delayed.rb +50 -0
  39. data/lib/sass/logger/log_level.rb +45 -0
  40. data/lib/sass/logger.rb +17 -0
  41. data/lib/sass/media.rb +210 -0
  42. data/lib/sass/plugin/compiler.rb +552 -0
  43. data/lib/sass/plugin/configuration.rb +134 -0
  44. data/lib/sass/plugin/generic.rb +15 -0
  45. data/lib/sass/plugin/merb.rb +48 -0
  46. data/lib/sass/plugin/rack.rb +60 -0
  47. data/lib/sass/plugin/rails.rb +47 -0
  48. data/lib/sass/plugin/staleness_checker.rb +199 -0
  49. data/lib/sass/plugin.rb +134 -0
  50. data/lib/sass/railtie.rb +10 -0
  51. data/lib/sass/repl.rb +57 -0
  52. data/lib/sass/root.rb +7 -0
  53. data/lib/sass/script/css_lexer.rb +33 -0
  54. data/lib/sass/script/css_parser.rb +36 -0
  55. data/lib/sass/script/functions.rb +3103 -0
  56. data/lib/sass/script/lexer.rb +518 -0
  57. data/lib/sass/script/parser.rb +1164 -0
  58. data/lib/sass/script/tree/funcall.rb +314 -0
  59. data/lib/sass/script/tree/interpolation.rb +220 -0
  60. data/lib/sass/script/tree/list_literal.rb +119 -0
  61. data/lib/sass/script/tree/literal.rb +49 -0
  62. data/lib/sass/script/tree/map_literal.rb +64 -0
  63. data/lib/sass/script/tree/node.rb +119 -0
  64. data/lib/sass/script/tree/operation.rb +149 -0
  65. data/lib/sass/script/tree/selector.rb +26 -0
  66. data/lib/sass/script/tree/string_interpolation.rb +125 -0
  67. data/lib/sass/script/tree/unary_operation.rb +69 -0
  68. data/lib/sass/script/tree/variable.rb +57 -0
  69. data/lib/sass/script/tree.rb +16 -0
  70. data/lib/sass/script/value/arg_list.rb +36 -0
  71. data/lib/sass/script/value/base.rb +258 -0
  72. data/lib/sass/script/value/bool.rb +35 -0
  73. data/lib/sass/script/value/callable.rb +25 -0
  74. data/lib/sass/script/value/color.rb +704 -0
  75. data/lib/sass/script/value/function.rb +19 -0
  76. data/lib/sass/script/value/helpers.rb +298 -0
  77. data/lib/sass/script/value/list.rb +135 -0
  78. data/lib/sass/script/value/map.rb +70 -0
  79. data/lib/sass/script/value/null.rb +44 -0
  80. data/lib/sass/script/value/number.rb +564 -0
  81. data/lib/sass/script/value/string.rb +138 -0
  82. data/lib/sass/script/value.rb +13 -0
  83. data/lib/sass/script.rb +66 -0
  84. data/lib/sass/scss/css_parser.rb +61 -0
  85. data/lib/sass/scss/parser.rb +1343 -0
  86. data/lib/sass/scss/rx.rb +134 -0
  87. data/lib/sass/scss/static_parser.rb +351 -0
  88. data/lib/sass/scss.rb +14 -0
  89. data/lib/sass/selector/abstract_sequence.rb +112 -0
  90. data/lib/sass/selector/comma_sequence.rb +195 -0
  91. data/lib/sass/selector/pseudo.rb +291 -0
  92. data/lib/sass/selector/sequence.rb +661 -0
  93. data/lib/sass/selector/simple.rb +124 -0
  94. data/lib/sass/selector/simple_sequence.rb +348 -0
  95. data/lib/sass/selector.rb +327 -0
  96. data/lib/sass/shared.rb +76 -0
  97. data/lib/sass/source/map.rb +209 -0
  98. data/lib/sass/source/position.rb +39 -0
  99. data/lib/sass/source/range.rb +41 -0
  100. data/lib/sass/stack.rb +140 -0
  101. data/lib/sass/supports.rb +225 -0
  102. data/lib/sass/tree/at_root_node.rb +83 -0
  103. data/lib/sass/tree/charset_node.rb +22 -0
  104. data/lib/sass/tree/comment_node.rb +82 -0
  105. data/lib/sass/tree/content_node.rb +9 -0
  106. data/lib/sass/tree/css_import_node.rb +68 -0
  107. data/lib/sass/tree/debug_node.rb +18 -0
  108. data/lib/sass/tree/directive_node.rb +59 -0
  109. data/lib/sass/tree/each_node.rb +24 -0
  110. data/lib/sass/tree/error_node.rb +18 -0
  111. data/lib/sass/tree/extend_node.rb +43 -0
  112. data/lib/sass/tree/for_node.rb +36 -0
  113. data/lib/sass/tree/function_node.rb +44 -0
  114. data/lib/sass/tree/if_node.rb +52 -0
  115. data/lib/sass/tree/import_node.rb +75 -0
  116. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  117. data/lib/sass/tree/media_node.rb +48 -0
  118. data/lib/sass/tree/mixin_def_node.rb +38 -0
  119. data/lib/sass/tree/mixin_node.rb +52 -0
  120. data/lib/sass/tree/node.rb +240 -0
  121. data/lib/sass/tree/prop_node.rb +162 -0
  122. data/lib/sass/tree/return_node.rb +19 -0
  123. data/lib/sass/tree/root_node.rb +44 -0
  124. data/lib/sass/tree/rule_node.rb +153 -0
  125. data/lib/sass/tree/supports_node.rb +38 -0
  126. data/lib/sass/tree/trace_node.rb +33 -0
  127. data/lib/sass/tree/variable_node.rb +36 -0
  128. data/lib/sass/tree/visitors/base.rb +72 -0
  129. data/lib/sass/tree/visitors/check_nesting.rb +173 -0
  130. data/lib/sass/tree/visitors/convert.rb +350 -0
  131. data/lib/sass/tree/visitors/cssize.rb +362 -0
  132. data/lib/sass/tree/visitors/deep_copy.rb +107 -0
  133. data/lib/sass/tree/visitors/extend.rb +64 -0
  134. data/lib/sass/tree/visitors/perform.rb +572 -0
  135. data/lib/sass/tree/visitors/set_options.rb +139 -0
  136. data/lib/sass/tree/visitors/to_css.rb +440 -0
  137. data/lib/sass/tree/warn_node.rb +18 -0
  138. data/lib/sass/tree/while_node.rb +18 -0
  139. data/lib/sass/util/multibyte_string_scanner.rb +151 -0
  140. data/lib/sass/util/normalized_map.rb +122 -0
  141. data/lib/sass/util/subset_map.rb +109 -0
  142. data/lib/sass/util/test.rb +9 -0
  143. data/lib/sass/util.rb +1137 -0
  144. data/lib/sass/version.rb +120 -0
  145. data/lib/sass.rb +102 -0
  146. data/rails/init.rb +1 -0
  147. metadata +283 -0
data/lib/sass/stack.rb ADDED
@@ -0,0 +1,140 @@
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
+ # Pushes a function frame onto the stack.
102
+ #
103
+ # @param filename [String] See \{Frame#filename}.
104
+ # @param line [String] See \{Frame#line}.
105
+ # @param name [String] See \{Frame#name}.
106
+ # @yield [] A block in which the new frame is on the stack.
107
+ def with_function(filename, line, name)
108
+ with_frame(filename, line, :function, name) {yield}
109
+ end
110
+
111
+ # Pushes a function frame onto the stack.
112
+ #
113
+ # @param filename [String] See \{Frame#filename}.
114
+ # @param line [String] See \{Frame#line}.
115
+ # @param name [String] See \{Frame#name}.
116
+ # @yield [] A block in which the new frame is on the stack.
117
+ def with_directive(filename, line, name)
118
+ with_frame(filename, line, :directive, name) {yield}
119
+ end
120
+
121
+ def to_s
122
+ (frames.reverse + [nil]).each_cons(2).each_with_index.
123
+ map do |(frame, caller), i|
124
+ "#{i == 0 ? 'on' : 'from'} line #{frame.line}" +
125
+ " of #{frame.filename || 'an unknown file'}" +
126
+ (caller && caller.name ? ", in `#{caller.name}'" : "")
127
+ end.join("\n")
128
+ end
129
+
130
+ private
131
+
132
+ def with_frame(filename, line, type, name = nil)
133
+ @frames.pop if @frames.last && @frames.last.type == :base
134
+ @frames.push(Frame.new(filename, line, type, name))
135
+ yield
136
+ ensure
137
+ @frames.pop unless type == :base && @frames.last && @frames.last.type != :base
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,225 @@
1
+ # A namespace for the `@supports` condition parse tree.
2
+ module Sass::Supports
3
+ # The abstract superclass of all Supports conditions.
4
+ class Condition
5
+ # Runs the SassScript in the supports condition.
6
+ #
7
+ # @param environment [Sass::Environment] The environment in which to run the script.
8
+ def perform(environment); Sass::Util.abstract(self); end
9
+
10
+ # Returns the CSS for this condition.
11
+ #
12
+ # @return [String]
13
+ def to_css; Sass::Util.abstract(self); end
14
+
15
+ # Returns the Sass/CSS code for this condition.
16
+ #
17
+ # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
18
+ # @return [String]
19
+ def to_src(options); Sass::Util.abstract(self); end
20
+
21
+ # Returns a deep copy of this condition and all its children.
22
+ #
23
+ # @return [Condition]
24
+ def deep_copy; Sass::Util.abstract(self); end
25
+
26
+ # Sets the options hash for the script nodes in the supports condition.
27
+ #
28
+ # @param options [{Symbol => Object}] The options has to set.
29
+ def options=(options); Sass::Util.abstract(self); end
30
+ end
31
+
32
+ # An operator condition (e.g. `CONDITION1 and CONDITION2`).
33
+ class Operator < Condition
34
+ # The left-hand condition.
35
+ #
36
+ # @return [Sass::Supports::Condition]
37
+ attr_accessor :left
38
+
39
+ # The right-hand condition.
40
+ #
41
+ # @return [Sass::Supports::Condition]
42
+ attr_accessor :right
43
+
44
+ # The operator ("and" or "or").
45
+ #
46
+ # @return [String]
47
+ attr_accessor :op
48
+
49
+ def initialize(left, right, op)
50
+ @left = left
51
+ @right = right
52
+ @op = op
53
+ end
54
+
55
+ def perform(env)
56
+ @left.perform(env)
57
+ @right.perform(env)
58
+ end
59
+
60
+ def to_css
61
+ "#{parens @left, @left.to_css} #{op} #{parens @right, @right.to_css}"
62
+ end
63
+
64
+ def to_src(options)
65
+ "#{parens @left, @left.to_src(options)} #{op} #{parens @right, @right.to_src(options)}"
66
+ end
67
+
68
+ def deep_copy
69
+ copy = dup
70
+ copy.left = @left.deep_copy
71
+ copy.right = @right.deep_copy
72
+ copy
73
+ end
74
+
75
+ def options=(options)
76
+ @left.options = options
77
+ @right.options = options
78
+ end
79
+
80
+ private
81
+
82
+ def parens(condition, str)
83
+ if condition.is_a?(Negation) || (condition.is_a?(Operator) && condition.op != op)
84
+ return "(#{str})"
85
+ else
86
+ return str
87
+ end
88
+ end
89
+ end
90
+
91
+ # A negation condition (`not CONDITION`).
92
+ class Negation < Condition
93
+ # The condition being negated.
94
+ #
95
+ # @return [Sass::Supports::Condition]
96
+ attr_accessor :condition
97
+
98
+ def initialize(condition)
99
+ @condition = condition
100
+ end
101
+
102
+ def perform(env)
103
+ @condition.perform(env)
104
+ end
105
+
106
+ def to_css
107
+ "not #{parens @condition.to_css}"
108
+ end
109
+
110
+ def to_src(options)
111
+ "not #{parens @condition.to_src(options)}"
112
+ end
113
+
114
+ def deep_copy
115
+ copy = dup
116
+ copy.condition = condition.deep_copy
117
+ copy
118
+ end
119
+
120
+ def options=(options)
121
+ condition.options = options
122
+ end
123
+
124
+ private
125
+
126
+ def parens(str)
127
+ return "(#{str})" if @condition.is_a?(Negation) || @condition.is_a?(Operator)
128
+ str
129
+ end
130
+ end
131
+
132
+ # A declaration condition (e.g. `(feature: value)`).
133
+ class Declaration < Condition
134
+ # @return [Sass::Script::Tree::Node] The feature name.
135
+ attr_accessor :name
136
+
137
+ # @!attribute resolved_name
138
+ # The name of the feature after any SassScript has been resolved.
139
+ # Only set once \{Tree::Visitors::Perform} has been run.
140
+ #
141
+ # @return [String]
142
+ attr_accessor :resolved_name
143
+
144
+ # The feature value.
145
+ #
146
+ # @return [Sass::Script::Tree::Node]
147
+ attr_accessor :value
148
+
149
+ # The value of the feature after any SassScript has been resolved.
150
+ # Only set once \{Tree::Visitors::Perform} has been run.
151
+ #
152
+ # @return [String]
153
+ attr_accessor :resolved_value
154
+
155
+ def initialize(name, value)
156
+ @name = name
157
+ @value = value
158
+ end
159
+
160
+ def perform(env)
161
+ @resolved_name = name.perform(env)
162
+ @resolved_value = value.perform(env)
163
+ end
164
+
165
+ def to_css
166
+ "(#{@resolved_name}: #{@resolved_value})"
167
+ end
168
+
169
+ def to_src(options)
170
+ "(#{@name.to_sass(options)}: #{@value.to_sass(options)})"
171
+ end
172
+
173
+ def deep_copy
174
+ copy = dup
175
+ copy.name = @name.deep_copy
176
+ copy.value = @value.deep_copy
177
+ copy
178
+ end
179
+
180
+ def options=(options)
181
+ @name.options = options
182
+ @value.options = options
183
+ end
184
+ end
185
+
186
+ # An interpolation condition (e.g. `#{$var}`).
187
+ class Interpolation < Condition
188
+ # The SassScript expression in the interpolation.
189
+ #
190
+ # @return [Sass::Script::Tree::Node]
191
+ attr_accessor :value
192
+
193
+ # The value of the expression after it's been resolved.
194
+ # Only set once \{Tree::Visitors::Perform} has been run.
195
+ #
196
+ # @return [String]
197
+ attr_accessor :resolved_value
198
+
199
+ def initialize(value)
200
+ @value = value
201
+ end
202
+
203
+ def perform(env)
204
+ @resolved_value = value.perform(env).to_s(:quote => :none)
205
+ end
206
+
207
+ def to_css
208
+ @resolved_value
209
+ end
210
+
211
+ def to_src(options)
212
+ @value.to_sass(options)
213
+ end
214
+
215
+ def deep_copy
216
+ copy = dup
217
+ copy.value = @value.deep_copy
218
+ copy
219
+ end
220
+
221
+ def options=(options)
222
+ @value.options = options
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,83 @@
1
+ module Sass
2
+ module Tree
3
+ # A dynamic node representing an `@at-root` directive.
4
+ #
5
+ # An `@at-root` directive with a selector is converted to an \{AtRootNode}
6
+ # containing a \{RuleNode} at parse time.
7
+ #
8
+ # @see Sass::Tree
9
+ class AtRootNode < Node
10
+ # The query for this node (e.g. `(without: media)`),
11
+ # interspersed with {Sass::Script::Tree::Node}s representing
12
+ # `#{}`-interpolation. Any adjacent strings will be merged
13
+ # together.
14
+ #
15
+ # This will be nil if the directive didn't have a query. In this
16
+ # case, {#resolved\_type} will automatically be set to
17
+ # `:without` and {#resolved\_rule} will automatically be set to `["rule"]`.
18
+ #
19
+ # @return [Array<String, Sass::Script::Tree::Node>]
20
+ attr_accessor :query
21
+
22
+ # The resolved type of this directive. `:with` or `:without`.
23
+ #
24
+ # @return [Symbol]
25
+ attr_accessor :resolved_type
26
+
27
+ # The resolved value of this directive -- a list of directives
28
+ # to either include or exclude.
29
+ #
30
+ # @return [Array<String>]
31
+ attr_accessor :resolved_value
32
+
33
+ # The number of additional tabs that the contents of this node
34
+ # should be indented.
35
+ #
36
+ # @return [Number]
37
+ attr_accessor :tabs
38
+
39
+ # Whether the last child of this node should be considered the
40
+ # end of a group.
41
+ #
42
+ # @return [Boolean]
43
+ attr_accessor :group_end
44
+
45
+ def initialize(query = nil)
46
+ super()
47
+ @query = Sass::Util.strip_string_array(Sass::Util.merge_adjacent_strings(query)) if query
48
+ @tabs = 0
49
+ end
50
+
51
+ # Returns whether or not the given directive is excluded by this
52
+ # node. `directive` may be "rule", which indicates whether
53
+ # normal CSS rules should be excluded.
54
+ #
55
+ # @param directive [String]
56
+ # @return [Boolean]
57
+ def exclude?(directive)
58
+ if resolved_type == :with
59
+ return false if resolved_value.include?('all')
60
+ !resolved_value.include?(directive)
61
+ else # resolved_type == :without
62
+ return true if resolved_value.include?('all')
63
+ resolved_value.include?(directive)
64
+ end
65
+ end
66
+
67
+ # Returns whether the given node is excluded by this node.
68
+ #
69
+ # @param node [Sass::Tree::Node]
70
+ # @return [Boolean]
71
+ def exclude_node?(node)
72
+ return exclude?(node.name.gsub(/^@/, '')) if node.is_a?(Sass::Tree::DirectiveNode)
73
+ return exclude?('keyframes') if node.is_a?(Sass::Tree::KeyframeRuleNode)
74
+ exclude?('rule') && node.is_a?(Sass::Tree::RuleNode)
75
+ end
76
+
77
+ # @see Node#bubbles?
78
+ def bubbles?
79
+ true
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,22 @@
1
+ module Sass::Tree
2
+ # A static node representing an unprocessed Sass `@charset` directive.
3
+ #
4
+ # @see Sass::Tree
5
+ class CharsetNode < Node
6
+ # The name of the charset.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :name
10
+
11
+ # @param name [String] see \{#name}
12
+ def initialize(name)
13
+ @name = name
14
+ super()
15
+ end
16
+
17
+ # @see Node#invisible?
18
+ def invisible?
19
+ true
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,82 @@
1
+ require 'sass/tree/node'
2
+
3
+ module Sass::Tree
4
+ # A static node representing a Sass comment (silent or loud).
5
+ #
6
+ # @see Sass::Tree
7
+ class CommentNode < Node
8
+ # The text of the comment, not including `/*` and `*/`.
9
+ # Interspersed with {Sass::Script::Tree::Node}s representing `#{}`-interpolation
10
+ # if this is a loud comment.
11
+ #
12
+ # @return [Array<String, Sass::Script::Tree::Node>]
13
+ attr_accessor :value
14
+
15
+ # The text of the comment
16
+ # after any interpolated SassScript has been resolved.
17
+ # Only set once \{Tree::Visitors::Perform} has been run.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :resolved_value
21
+
22
+ # The type of the comment. `:silent` means it's never output to CSS,
23
+ # `:normal` means it's output in every compile mode except `:compressed`,
24
+ # and `:loud` means it's output even in `:compressed`.
25
+ #
26
+ # @return [Symbol]
27
+ attr_accessor :type
28
+
29
+ # @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
30
+ # @param type [Symbol] See \{#type}
31
+ def initialize(value, type)
32
+ @value = Sass::Util.with_extracted_values(value) {|str| normalize_indentation str}
33
+ @type = type
34
+ super()
35
+ end
36
+
37
+ # Compares the contents of two comments.
38
+ #
39
+ # @param other [Object] The object to compare with
40
+ # @return [Boolean] Whether or not this node and the other object
41
+ # are the same
42
+ def ==(other)
43
+ self.class == other.class && value == other.value && type == other.type
44
+ end
45
+
46
+ # Returns `true` if this is a silent comment
47
+ # or the current style doesn't render comments.
48
+ #
49
+ # Comments starting with ! are never invisible (and the ! is removed from the output.)
50
+ #
51
+ # @return [Boolean]
52
+ def invisible?
53
+ case @type
54
+ when :loud; false
55
+ when :silent; true
56
+ else; style == :compressed
57
+ end
58
+ end
59
+
60
+ # Returns the number of lines in the comment.
61
+ #
62
+ # @return [Integer]
63
+ def lines
64
+ @value.inject(0) do |s, e|
65
+ next s + e.count("\n") if e.is_a?(String)
66
+ next s
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def normalize_indentation(str)
73
+ ind = str.split("\n").inject(str[/^[ \t]*/].split("")) do |pre, line|
74
+ line[/^[ \t]*/].split("").zip(pre).inject([]) do |arr, (a, b)|
75
+ break arr if a != b
76
+ arr << a
77
+ end
78
+ end.join
79
+ str.gsub(/^#{ind}/, '')
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,9 @@
1
+ module Sass
2
+ module Tree
3
+ # A node representing the placement within a mixin of the include statement's content.
4
+ #
5
+ # @see Sass::Tree
6
+ class ContentNode < Node
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,68 @@
1
+ module Sass::Tree
2
+ # A node representing an `@import` rule that's importing plain CSS.
3
+ #
4
+ # @see Sass::Tree
5
+ class CssImportNode < DirectiveNode
6
+ # The URI being imported, either as a plain string or an interpolated
7
+ # script string.
8
+ #
9
+ # @return [String, Sass::Script::Tree::Node]
10
+ attr_accessor :uri
11
+
12
+ # The text of the URI being imported after any interpolated SassScript has
13
+ # been resolved. Only set once {Tree::Visitors::Perform} has been run.
14
+ #
15
+ # @return [String]
16
+ attr_accessor :resolved_uri
17
+
18
+ # The supports condition for this import.
19
+ #
20
+ # @return [Sass::Supports::Condition]
21
+ attr_accessor :supports_condition
22
+
23
+ # The media query for this rule, interspersed with
24
+ # {Sass::Script::Tree::Node}s representing `#{}`-interpolation. Any adjacent
25
+ # strings will be merged together.
26
+ #
27
+ # @return [Array<String, Sass::Script::Tree::Node>]
28
+ attr_accessor :query
29
+
30
+ # The media query for this rule, without any unresolved interpolation.
31
+ # It's only set once {Tree::Visitors::Perform} has been run.
32
+ #
33
+ # @return [Sass::Media::QueryList]
34
+ attr_accessor :resolved_query
35
+
36
+ # @param uri [String, Sass::Script::Tree::Node] See \{#uri}
37
+ # @param query [Array<String, Sass::Script::Tree::Node>] See \{#query}
38
+ # @param supports_condition [Sass::Supports::Condition] See \{#supports_condition}
39
+ def initialize(uri, query = [], supports_condition = nil)
40
+ @uri = uri
41
+ @query = query
42
+ @supports_condition = supports_condition
43
+ super('')
44
+ end
45
+
46
+ # @param uri [String] See \{#resolved_uri}
47
+ # @return [CssImportNode]
48
+ def self.resolved(uri)
49
+ node = new(uri)
50
+ node.resolved_uri = uri
51
+ node
52
+ end
53
+
54
+ # @see DirectiveNode#value
55
+ def value; raise NotImplementedError; end
56
+
57
+ # @see DirectiveNode#resolved_value
58
+ def resolved_value
59
+ @resolved_value ||=
60
+ begin
61
+ str = "@import #{resolved_uri}"
62
+ str << " supports(#{supports_condition.to_css})" if supports_condition
63
+ str << " #{resolved_query.to_css}" if resolved_query
64
+ str
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ module Sass
2
+ module Tree
3
+ # A dynamic node representing a Sass `@debug` statement.
4
+ #
5
+ # @see Sass::Tree
6
+ class DebugNode < Node
7
+ # The expression to print.
8
+ # @return [Script::Tree::Node]
9
+ attr_accessor :expr
10
+
11
+ # @param expr [Script::Tree::Node] The expression to print
12
+ def initialize(expr)
13
+ @expr = expr
14
+ super()
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ module Sass::Tree
2
+ # A static node representing an unprocessed Sass `@`-directive.
3
+ # Directives known to Sass, like `@for` and `@debug`,
4
+ # are handled by their own nodes;
5
+ # only CSS directives like `@media` and `@font-face` become {DirectiveNode}s.
6
+ #
7
+ # `@import` and `@charset` are special cases;
8
+ # they become {ImportNode}s and {CharsetNode}s, respectively.
9
+ #
10
+ # @see Sass::Tree
11
+ class DirectiveNode < Node
12
+ # The text of the directive, `@` and all, with interpolation included.
13
+ #
14
+ # @return [Array<String, Sass::Script::Tree::Node>]
15
+ attr_accessor :value
16
+
17
+ # The text of the directive after any interpolated SassScript has been resolved.
18
+ # Only set once \{Tree::Visitors::Perform} has been run.
19
+ #
20
+ # @return [String]
21
+ attr_accessor :resolved_value
22
+
23
+ # @see RuleNode#tabs
24
+ attr_accessor :tabs
25
+
26
+ # @see RuleNode#group_end
27
+ attr_accessor :group_end
28
+
29
+ # @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
30
+ def initialize(value)
31
+ @value = value
32
+ @tabs = 0
33
+ super()
34
+ end
35
+
36
+ # @param value [String] See \{#resolved_value}
37
+ # @return [DirectiveNode]
38
+ def self.resolved(value)
39
+ node = new([value])
40
+ node.resolved_value = value
41
+ node
42
+ end
43
+
44
+ # @return [String] The name of the directive, including `@`.
45
+ def name
46
+ @name ||= value.first.gsub(/ .*$/, '')
47
+ end
48
+
49
+ # Strips out any vendor prefixes and downcases the directive name.
50
+ # @return [String] The normalized name of the directive.
51
+ def normalized_name
52
+ @normalized_name ||= name.gsub(/^(@)(?:-[a-zA-Z0-9]+-)?/, '\1').downcase
53
+ end
54
+
55
+ def bubbles?
56
+ has_children
57
+ end
58
+ end
59
+ end