less_to_sass 0.1.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 (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +70 -0
  4. data/bin/less2sass +12 -0
  5. data/bin/sass2less +12 -0
  6. data/lib/less2sass/constants.rb +5 -0
  7. data/lib/less2sass/error.rb +100 -0
  8. data/lib/less2sass/exec/base.rb +83 -0
  9. data/lib/less2sass/exec/conversion.rb +102 -0
  10. data/lib/less2sass/exec.rb +2 -0
  11. data/lib/less2sass/js/less_parser.js +48 -0
  12. data/lib/less2sass/less/ast_handler.rb +33 -0
  13. data/lib/less2sass/less/environment.rb +212 -0
  14. data/lib/less2sass/less/parser.rb +131 -0
  15. data/lib/less2sass/less/tree/alpha_node.rb +9 -0
  16. data/lib/less2sass/less/tree/anonymous_node.rb +43 -0
  17. data/lib/less2sass/less/tree/assignment_node.rb +10 -0
  18. data/lib/less2sass/less/tree/attribute_node.rb +11 -0
  19. data/lib/less2sass/less/tree/call_node.rb +65 -0
  20. data/lib/less2sass/less/tree/color_node.rb +27 -0
  21. data/lib/less2sass/less/tree/combinator_node.rb +18 -0
  22. data/lib/less2sass/less/tree/comment_node.rb +58 -0
  23. data/lib/less2sass/less/tree/condition_node.rb +13 -0
  24. data/lib/less2sass/less/tree/detached_ruleset_node.rb +10 -0
  25. data/lib/less2sass/less/tree/dimension_node.rb +26 -0
  26. data/lib/less2sass/less/tree/directive_node.rb +40 -0
  27. data/lib/less2sass/less/tree/element_node.rb +32 -0
  28. data/lib/less2sass/less/tree/expression_node.rb +73 -0
  29. data/lib/less2sass/less/tree/extend_node.rb +14 -0
  30. data/lib/less2sass/less/tree/import_node.rb +14 -0
  31. data/lib/less2sass/less/tree/keyword_node.rb +49 -0
  32. data/lib/less2sass/less/tree/media_node.rb +12 -0
  33. data/lib/less2sass/less/tree/mixin_call_node.rb +13 -0
  34. data/lib/less2sass/less/tree/mixin_definition_node.rb +24 -0
  35. data/lib/less2sass/less/tree/negative_node.rb +9 -0
  36. data/lib/less2sass/less/tree/node.rb +212 -0
  37. data/lib/less2sass/less/tree/operation_node.rb +63 -0
  38. data/lib/less2sass/less/tree/paren_node.rb +9 -0
  39. data/lib/less2sass/less/tree/quoted_node.rb +64 -0
  40. data/lib/less2sass/less/tree/rule_node.rb +119 -0
  41. data/lib/less2sass/less/tree/ruleset_call_node.rb +9 -0
  42. data/lib/less2sass/less/tree/ruleset_node.rb +82 -0
  43. data/lib/less2sass/less/tree/selector_node.rb +27 -0
  44. data/lib/less2sass/less/tree/unicode_descriptor_node.rb +9 -0
  45. data/lib/less2sass/less/tree/unit_node.rb +17 -0
  46. data/lib/less2sass/less/tree/url_node.rb +22 -0
  47. data/lib/less2sass/less/tree/value_node.rb +53 -0
  48. data/lib/less2sass/less/tree/variable_node.rb +43 -0
  49. data/lib/less2sass/less/tree.rb +34 -0
  50. data/lib/less2sass/less.rb +2 -0
  51. data/lib/less2sass/sass/ast_handler.rb +57 -0
  52. data/lib/less2sass/sass/parser.rb +20 -0
  53. data/lib/less2sass/sass.rb +2 -0
  54. data/lib/less2sass/util.rb +36 -0
  55. data/lib/less2sass.rb +9 -0
  56. metadata +163 -0
@@ -0,0 +1,212 @@
1
+ module Less2Sass
2
+ module Less
3
+ # The lexical environment for Less.
4
+ # Keeps track of variable and mixin definitions.
5
+ # The environment differentiates between simple
6
+ # and constructed(dynamic) variable definitions.
7
+ #
8
+ # A new environment is created for each level of Less nesting.
9
+ # This allows variables to be lexically scoped.
10
+ # Each environment refers to the environment in the upper scope,
11
+ # unless it is the global environment, thus having access to
12
+ # variables defined in enclosing scopes. New variables are defined
13
+ # locally.
14
+ class Environment
15
+ # The enclosing environment, or nil if it's the
16
+ # global environment.
17
+ #
18
+ # @return [Less2Sass::Less::Environment]
19
+ attr_reader :parent
20
+
21
+ # Ordered list of static variable definitions.
22
+ # Examples:
23
+ # - @var: 50px;
24
+ #
25
+ # @return [Array<Less2Sass::Less::Tree::RuleNode>]
26
+ attr_reader :static_var_def_rules
27
+
28
+ # Ordered list of constructed variable definitions.
29
+ # Examples:
30
+ # - @var: @var2;
31
+ # - @var1: @var2 + 10px;
32
+ #
33
+ # @return [Array<Less2Sass::Less::Tree::RuleNode>]
34
+ attr_reader :dynamic_var_def_rules
35
+
36
+ # A list of mixin calls.
37
+ #
38
+ # @return [Array<Less2Sass::Less::Tree::RuleNode>]
39
+ attr_reader :mixin_call_rules
40
+
41
+ # @param parent (see :parent)
42
+ def initialize(parent = nil)
43
+ @parent = parent
44
+ @variables_to_reorder = {}
45
+ @static_var_def_rules = {}
46
+ @dynamic_var_def_rules = []
47
+ @rules = []
48
+ @rest = []
49
+ @mixin_call_rules = []
50
+ end
51
+
52
+ # Places an array of nodes into this environment.
53
+ #
54
+ # @param [Array<Less2Sass::Less::Tree::Node>] objs
55
+ # child nodes of a context creator node
56
+ # @see #put
57
+ def set_environment(objs)
58
+ objs.each { |obj| set(obj) }
59
+ end
60
+
61
+ # Builds the `dynamic_var_def_rules` ordered array.
62
+ #
63
+ # Processes lazy loaded variables by importing their definition
64
+ # if they are overridden of this environment's scope. Furthermore,
65
+ # it reorders the variable definitions.
66
+ # The only rule is, that the referenced variables should be
67
+ # placed before their first referral. If no variable definition
68
+ # references the the current iteration's variable, it shall be
69
+ # put at the end of the array, since it could reference any of the
70
+ # previously defined variables.
71
+ #
72
+ # @note does not detect recursive variable definitions
73
+ # @return [void]
74
+ # @todo implement detection in future releases
75
+ def build
76
+ process_lazy_loading
77
+ to_reorder = @variables_to_reorder.values
78
+ unless to_reorder.empty?
79
+ @dynamic_var_def_rules << to_reorder.shift
80
+ to_reorder.each do |var|
81
+ @dynamic_var_def_rules.each_with_index do |o_var, index|
82
+ if o_var.references?(var.name)
83
+ @dynamic_var_def_rules.insert(index, var)
84
+ break
85
+ end
86
+ @dynamic_var_def_rules.insert(index + 1, var) if @dynamic_var_def_rules.last.eql?(o_var)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ # Reorders the child nodes of another node, that creates an
93
+ # environment, resp. an execution context.
94
+ #
95
+ # The order should be:
96
+ #
97
+ # 1. Simple/static variables
98
+ # These do not reference any other variable(s) in their definition.
99
+ #
100
+ # 2. Complex/dynamic variables
101
+ # These can reference either the static variables in the same context,
102
+ # other variables from the outer environment, or each other without any
103
+ # cross-reference, also known as recursive reference.
104
+ #
105
+ # TODO: maybe directives should be also sorted out and put before the mixin calls
106
+ # 3. Other nodes (directives, rules, rule sets, etc.)
107
+ #
108
+ # 4. Rules (selector + declarations)
109
+ # The Sass rules (Less rule sets) create a new environment and could redefine
110
+ # the variables' used after their declaration.
111
+ #
112
+ # 5. Mixin calls
113
+ # These mixins can reference the rule sets created one step above.
114
+ #
115
+ # @return [Array<Less2Sass::Less::Tree::Node>] the reordered list of nodes
116
+ def get_ordered_child_nodes
117
+ @static_var_def_rules.values + @dynamic_var_def_rules + @rest + @rules + @mixin_call_rules
118
+ end
119
+
120
+ def variable_defined?(name)
121
+ @static_var_def_rules[name] || @variables_to_reorder[name]
122
+ end
123
+
124
+ def find_variable_definition_if_dynamic(name)
125
+ variable = @variables_to_reorder[name]
126
+ return variable if variable
127
+ @parent ? @parent.find_variable_definition_if_dynamic(name) : nil
128
+ end
129
+
130
+ private
131
+
132
+ # Puts the nodes of this environment's scope into
133
+ # the appropriate container.
134
+ #
135
+ # Sorts out the variable definitions and mixin calls
136
+ # from the rest. The variable definitions are saved
137
+ # into hashes under their names as keys. If a variable
138
+ # is defined multiple times, only the last definition
139
+ # will be kept.
140
+ #
141
+ # @param [Less2Sass::Less::Tree::Node] obj
142
+ # the rule to be placed into the environment
143
+ # @return [void]
144
+ def set(obj)
145
+ if obj.is_a?(Less2Sass::Less::Tree::RulesetNode)
146
+ @rules << obj
147
+ elsif obj.is_a?(Less2Sass::Less::Tree::RuleNode)
148
+ if obj.is_variable_definition?
149
+ referenced_vars = obj.get_referenced_variable_names
150
+ if referenced_vars.empty?
151
+ @static_var_def_rules[obj.name] = obj
152
+ else
153
+ obj.ref_vars = referenced_vars
154
+ @variables_to_reorder[obj.name] = obj
155
+ end
156
+ else
157
+ @rest << obj
158
+ end
159
+ elsif obj.is_a?(Less2Sass::Less::Tree::MixinCallNode)
160
+ @mixin_call_rules << obj
161
+ elsif obj.is_a?(Less2Sass::Less::Tree::SelectorNode)
162
+ return # ignore selectors
163
+ else
164
+ @rest << obj
165
+ end
166
+ end
167
+
168
+ # Processes lazy loaded variables by importing their definition
169
+ # if they are overridden of this environment's scope.
170
+ #
171
+ # Imports all those variable definitions, whose
172
+ # members are overridden by the variable definitions
173
+ # of the current scope.
174
+ #
175
+ # @return [Void]
176
+ def process_lazy_loading
177
+ rules_to_check = @dynamic_var_def_rules + @rules + @rest + @mixin_call_rules
178
+ rules_to_check.each do |rule|
179
+ rules_to_check += [rule.selectors].flatten if rule.is_a?(Less2Sass::Less::Tree::RulesetNode)
180
+ rule.ref_vars.each do |variable|
181
+ import_definitions_of(variable)
182
+ end unless rule.creates_context?
183
+ end
184
+ end
185
+
186
+ # Imports the appropriate variable definitions
187
+ # into the current scope.
188
+ #
189
+ # Those definitions will be imported, that contain a
190
+ # reference to a variable, that is redefined in
191
+ # the current scope. If such a variable is not redefined,
192
+ # its definition is looked for such a variable.
193
+ # The process continues recursively just like the process
194
+ # of lazy loading.
195
+ #
196
+ # @param [String] name the variable's name
197
+ # @return [Void]
198
+ def import_definitions_of(name)
199
+ if @parent
200
+ definition = @parent.find_variable_definition_if_dynamic(name)
201
+ definition.ref_vars.each do |var|
202
+ if variable_defined?(var)
203
+ @variables_to_reorder[definition.name] = definition unless @variables_to_reorder[definition.name]
204
+ else
205
+ import_definitions_of(var)
206
+ end
207
+ end if definition
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,131 @@
1
+ require 'less2sass/less/tree'
2
+ require 'json'
3
+
4
+ module Less2Sass
5
+ module Less
6
+ # The parser for Less.
7
+ # It parses a Less project into a tree of {Less2Sass::Less::Tree::Node}s.
8
+ # The project is meant as one or more files.
9
+ class Parser
10
+ # @param [File, IO] input The source project to parse.
11
+ def initialize(input)
12
+ @input = input
13
+ @options = input == $stdin ? "-stdin \"#{Util.read_stdin_as_multiline_arg}\"" : File.expand_path(input)
14
+ end
15
+
16
+ # Checks, whether the Less project can be compiled.
17
+ #
18
+ # @return [void]
19
+ # @raise [Less2Sass::LessCompilationError] if the project can't be compiled.
20
+ def check_syntax
21
+ response = `lessc --lint #{File.expand_path(@input)} 2>&1 >/dev/null`
22
+ raise LessCompilationError, response unless response.empty?
23
+ end
24
+
25
+ # Parses a Less project.
26
+ #
27
+ # @return [Less2Sass::Less::Tree::Node] The root node of the project tree
28
+ # @raise [Less2Sass::LessSyntaxError] if there's a syntax error in the document
29
+ # @raise [Less2Sass::LessImportNotFoundError] if any of the imports can't be found
30
+ def parse
31
+ string_ast = `node #{Util.scope(PARSER)} #{@options}`
32
+ json_ast = JSON.parse(string_ast)
33
+ if json_ast['class'] == 'error'
34
+ raise LessImportNotFoundError, json_ast if json_ast['type'] == 'File'
35
+ raise LessSyntaxError, json_ast if json_ast['type'] == 'Parse'
36
+ end
37
+ build_tree(json_ast)
38
+ end
39
+
40
+ # Converts the parsed Less project from JSON object
41
+ # to a {Less2Sass::Less::Tree::Node} representation.
42
+ #
43
+ # Note, that this method recursively calls itself.
44
+ #
45
+ # @param [Hash] json the JSON object representing the Less AST
46
+ # @param [Less2Sass::Less::Tree::Node] parent the respective parent node
47
+ # of the currently processed node.
48
+ # @return [Less2Sass::Less::Tree::Node] The root node of the project tree
49
+ # @raise [Less2Sass::LessASTParserError] if something unexpected happens.
50
+ def build_tree(json, parent = nil)
51
+ node = create_node(json['class'], parent)
52
+
53
+ json.each do |k, v|
54
+ key = instance_var_sym(k)
55
+
56
+ if v.is_a?(Hash)
57
+ # Is the hash a node, or a simple value?
58
+ if node?(v)
59
+ # The node should be referenced under the original key, as well as
60
+ # in the child nodes, so it's easier to handle conversion
61
+ # and still be able to traverse the full tree. Since these would be
62
+ # the same objects, the changes made during the transformation
63
+ # process would be reflected at both places.
64
+ subnode = build_tree(v, node)
65
+ node.instance_variable_set(key, subnode)
66
+ node << subnode
67
+ else
68
+ node.instance_variable_set(key, v)
69
+ end
70
+ elsif v.is_a?(Array)
71
+ if node?(v[0])
72
+ # It's an array of nodes
73
+ subnodes = []
74
+ v.each do |item|
75
+ # Something is very wrong if the item is not another node
76
+ raise LessASTParserError, item.class.to_s unless node?(item)
77
+ subnode = build_tree(item, node)
78
+ subnodes << subnode
79
+ node << subnode
80
+ end
81
+ value = subnodes.length == 1 ? subnodes[0] : subnodes
82
+ node.instance_variable_set(key, value)
83
+ else
84
+ # It's a simple array containing other values than nodes
85
+ node.instance_variable_set(key, v)
86
+ end
87
+ else
88
+ # Simple key-value pair
89
+ next if k == 'class'
90
+ node.instance_variable_set(key, v)
91
+ end
92
+ end
93
+
94
+ node
95
+ end
96
+
97
+ private
98
+
99
+ PARSER = 'lib/less2sass/js/less_parser.js'.freeze
100
+
101
+ # Creates the node in a Ruby object-like representation.
102
+ #
103
+ # @param [String] class_name the classname of the node to be created
104
+ # @param [Less2Sass::Less::Tree::Node] parent the parent node of the one
105
+ # currently being created
106
+ # @return [Less2Sass::Less::Tree::Node] an AST node
107
+ def create_node(class_name, parent)
108
+ Tree.const_get(class_name.to_s + 'Node')
109
+ .new(parent)
110
+ end
111
+
112
+ # Creates a symbol as reference to a member object,
113
+ # so it can be set dynamically.
114
+ #
115
+ # @param [String] key the string representation
116
+ # of an object's member
117
+ # @return [Symbol] the symbolic reference to an object's member
118
+ def instance_var_sym(key)
119
+ "@#{key}".to_sym
120
+ end
121
+
122
+ def node?(json)
123
+ json.is_a?(Hash) && json.key?('class')
124
+ end
125
+
126
+ def hash_value?(hash)
127
+ !hash.key?('class')
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,9 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ class AlphaNode < Node
5
+ attr_accessor :value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,43 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Represents a CSS literal in Less.
5
+ #
6
+ # Its Sass equivalent is {::Sass::Script::Value::Base}
7
+ # wrapped in {::Sass::Script::Tree::Literal}.
8
+ class AnonymousNode < Node
9
+ attr_accessor :value
10
+ attr_accessor :index
11
+ attr_accessor :mapLines
12
+ attr_accessor :currentFileInfo
13
+ attr_accessor :rulesetLike
14
+
15
+ # Converts to a {::Sass::Script::Tree::Literal} that
16
+ # encapsulates a {::Sass::Script::Value::Base}.
17
+ #
18
+ # @note Never seen a different equivalent than String
19
+ # or a Number but can't be sure.
20
+ # @raise FeatureConversionError if `@value` not a String
21
+ # or a Numeric.
22
+ # @return [::Sass::Script::Tree::Literal]
23
+ # @see Node#to_sass
24
+ def to_sass
25
+ subnode ||=
26
+ begin
27
+ if @value.is_a?(String)
28
+ # Always an :identifier - the default value of the 2nd param
29
+ ::Sass::Script::Value::String.new(@value)
30
+ elsif @value.is_a?(Numeric)
31
+ # Anonymous nodes do not have a numerator nor a denominator
32
+ ::Sass::Script::Value::Number.new(@value)
33
+ else
34
+ raise FeatureConversionError, self
35
+ end
36
+ end
37
+ return subnode if subnode.is_a?(::Sass::Script::Tree::Literal)
38
+ node(::Sass::Script::Tree::Literal.new(subnode), line)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ class AssignmentNode < Node
5
+ attr_accessor :key
6
+ attr_accessor :value
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ class AttributeNode < Node
5
+ attr_accessor :key
6
+ attr_accessor :op
7
+ attr_accessor :value
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,65 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Represents a function call node. It can be either
5
+ # a CSS or a Less built-in function.
6
+ #
7
+ # Its Sass equivalent is {::Sass::Script::Tree::Funcall}.
8
+ class CallNode < Node
9
+ attr_accessor :name
10
+ attr_accessor :args
11
+ attr_accessor :index
12
+ attr_accessor :currentFileInfo
13
+
14
+ # TODO: Map Less built-in functions to Sass built-in functions, null if there is no equivalent
15
+
16
+ MISC_FUNCTIONS = %w(color image-size image-width image-height
17
+ convert data-uri default unit get-unit svg-gradient).freeze
18
+
19
+ STRING_FUNCTIONS = %w(escape e % replace).freeze
20
+
21
+ LIST_FUNCTIONS = %w(length extract).freeze
22
+
23
+ MATH_FUNCTIONS = %w(ceil floor percentage round sqrt abs sin
24
+ asin cos acos tan atan pi pow mod min max).freeze
25
+
26
+ TYPE_FUNCTIONS = %w(isnumber isstring iscolor iskeyword isurl
27
+ ispixel isem ispercentage isunit isruleset).freeze
28
+
29
+ COLOR_DEFINITION_FUNCTIONS = %w(rgb rgba argb hsl hsla hsv hsva).freeze
30
+
31
+ COLOR_CHANNEL_FUNCTIONS = %w(hue saturation lightness hsvhue hsvsaturation
32
+ hsvvalue red green blue alpha luma luminance).freeze
33
+
34
+ COLOR_OPERATION_FUNCTIONS = %w(saturate desaturate lighten darken fadein
35
+ fadeout fade spin mix tint shade greyscale contrast).freeze
36
+
37
+ COLOR_BLENDING_FUNCTIONS = %w(multiply screen overlay softlight hardlight
38
+ difference exclusion average negation).freeze
39
+
40
+ # @todo built-in functions should be converted by the mapping
41
+ # if there is no equivalent, a custom conversion should be implemented.
42
+ # If the {Hash} does not contain the function, most probably, it's a
43
+ # CSS built-in function and it should be copied as it is.
44
+ #
45
+ # @note In its current version it could output unrecognizable functions
46
+ # by the Sass compiler and/or interpreter.
47
+ # @return [::Sass::Script::Tree::Funcall]
48
+ # @see Node#to_sass
49
+ def to_sass
50
+ node(::Sass::Script::Tree::Funcall.new(@name, get_args, ::Sass::Util::NormalizedMap.new, nil, nil), line)
51
+ end
52
+
53
+ private
54
+
55
+ def get_args
56
+ if @args.is_a?(Array)
57
+ @args.inject([]) { |args, arg| args << arg.to_sass }.flatten
58
+ else
59
+ [@args.to_sass]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,27 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # CSS color representation.
5
+ #
6
+ # Usually appears at variable definitions.
7
+ # Example:
8
+ # - `@color: #fff;` rule contains ColorNode
9
+ # - `color: #fff;` property declaration does
10
+ # not contain ColorNode
11
+ #
12
+ # The Sass equivalent is {::Sass::Script::Value::Color}.
13
+ class ColorNode < Node
14
+ attr_accessor :rgb
15
+ attr_accessor :alpha
16
+ attr_accessor :value
17
+
18
+ # @return [::Sass::Script::Value::Color]
19
+ # @see Node#to_sass
20
+ def to_sass
21
+ color = node(::Sass::Script::Value::Color.new(@rgb, @value), nil)
22
+ node(::Sass::Script::Tree::Literal.new(color), line)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Represents the separator between some nodes.
5
+ # No equivalent in Sass.
6
+ class CombinatorNode < Node
7
+ # @return [String]
8
+ attr_accessor :value
9
+ # @return [Boolean]
10
+ attr_accessor :emptyOrWhitespace
11
+
12
+ def to_s
13
+ @value
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,58 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Represents either a single-line or a block comment
5
+ # Unfortunately, there is no way to find out, whether
6
+ # the comment has been put on a new line or it just
7
+ # continues on the same line as a rule, for instance.
8
+ #
9
+ # Examples:
10
+ # color: #fff; //line comment
11
+ # or
12
+ # color: #fff;
13
+ # //line comment
14
+ #
15
+ # The AST will be absolutely identical in both cases.
16
+ # So let's come up with a convention:
17
+ # - line comments will be put on the same line as
18
+ # the previous node
19
+ # - block comments will be put on new lines
20
+ class CommentNode < Node
21
+ attr_accessor :value
22
+ attr_accessor :isLineComment
23
+ attr_accessor :currentFileInfo
24
+
25
+ def to_sass
26
+ line = line(@isLineComment ? :current : :new)
27
+ node(::Sass::Tree::CommentNode.new([@value], type), line)
28
+ end
29
+
30
+ private
31
+
32
+ # Specifies the type of the comment.
33
+ #
34
+ # There are 3 types of comments in Sass:
35
+ # - :normal (output to CSS except in :compressed mode)
36
+ # - :silent (never output to CSS)
37
+ # - :loud (output to CSS even in :compressed mode)
38
+ #
39
+ # To evaluate the type correctly, the original implementation
40
+ # needs to be used.
41
+ # @see https://github.com/sass/sass/blob/63586f1e51c0aec47a7afcc8cd17aa03f32f0a29/lib/sass/engine.rb#L764-765
42
+ #
43
+ # @return [Symbol] the type of Sass comment
44
+ def type
45
+ silent = @value[1] == ::Sass::Engine::SASS_COMMENT_CHAR
46
+ loud = !silent && @value[2] == ::Sass::Engine::SASS_LOUD_COMMENT_CHAR
47
+ if silent
48
+ :silent
49
+ elsif loud
50
+ :loud
51
+ else
52
+ :normal
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ class ConditionNode < Node
5
+ attr_accessor :op
6
+ attr_accessor :lvalue
7
+ attr_accessor :rvalue
8
+ attr_accessor :index
9
+ attr_accessor :negate
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ class DetachedRulesetNode < Node
5
+ attr_accessor :ruleset
6
+ attr_accessor :frames
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Representation of a number and a unit.
5
+ # The Sass equivalent is the {::Sass::Script::Value::Number}
6
+ # or {::Sass::Script::Tree::Literal} if the dimension is a part
7
+ # of an {ExpressionNode}'s {OperationNode}.
8
+ class DimensionNode < Node
9
+ attr_accessor :value
10
+ attr_accessor :unit
11
+
12
+ # @see Node#to_sass
13
+ def to_sass
14
+ numerator = @unit.is_a?(UnitNode) ? @unit.numerator : @unit['numerator']
15
+ denominator = @unit.is_a?(UnitNode) ? @unit.denominator : @unit['denominator']
16
+ dimension = ::Sass::Script::Value::Number.new(@value, numerator, denominator)
17
+ node(::Sass::Script::Tree::Literal.new(dimension), line)
18
+ end
19
+
20
+ def to_s
21
+ @value.to_s + @unit.to_s
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ module Less2Sass
2
+ module Less
3
+ module Tree
4
+ # Represents a static CSS directive.
5
+ #
6
+ # Examples:
7
+ # - @charset
8
+ # - @namespace
9
+ # - @keyframes
10
+ # - @counter-style
11
+ # - @document
12
+ # - @supports
13
+ #
14
+ # The Sass equivalent is {::Sass::Tree::DirectiveNode}.
15
+ # @note Sits on a new line.
16
+ # @see Node
17
+ class DirectiveNode < Node
18
+ attr_accessor :name
19
+ attr_accessor :value
20
+ attr_accessor :rules
21
+ attr_accessor :index
22
+ attr_accessor :currentFileInfo
23
+ attr_accessor :debugInfo
24
+ attr_accessor :isRooted
25
+
26
+ # @return [::Sass::Tree::DirectiveNode]
27
+ # @see Node#to_sass
28
+ def to_sass
29
+ node = node(::Sass::Tree::DirectiveNode.new(value), line(:new))
30
+ @rules.rules.each { |c| node << c.to_sass } # Not all children should be passed
31
+ node
32
+ end
33
+
34
+ def value
35
+ @value.empty? ? [@name] : [@name + ' ', @value.to_s]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end