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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +70 -0
- data/bin/less2sass +12 -0
- data/bin/sass2less +12 -0
- data/lib/less2sass/constants.rb +5 -0
- data/lib/less2sass/error.rb +100 -0
- data/lib/less2sass/exec/base.rb +83 -0
- data/lib/less2sass/exec/conversion.rb +102 -0
- data/lib/less2sass/exec.rb +2 -0
- data/lib/less2sass/js/less_parser.js +48 -0
- data/lib/less2sass/less/ast_handler.rb +33 -0
- data/lib/less2sass/less/environment.rb +212 -0
- data/lib/less2sass/less/parser.rb +131 -0
- data/lib/less2sass/less/tree/alpha_node.rb +9 -0
- data/lib/less2sass/less/tree/anonymous_node.rb +43 -0
- data/lib/less2sass/less/tree/assignment_node.rb +10 -0
- data/lib/less2sass/less/tree/attribute_node.rb +11 -0
- data/lib/less2sass/less/tree/call_node.rb +65 -0
- data/lib/less2sass/less/tree/color_node.rb +27 -0
- data/lib/less2sass/less/tree/combinator_node.rb +18 -0
- data/lib/less2sass/less/tree/comment_node.rb +58 -0
- data/lib/less2sass/less/tree/condition_node.rb +13 -0
- data/lib/less2sass/less/tree/detached_ruleset_node.rb +10 -0
- data/lib/less2sass/less/tree/dimension_node.rb +26 -0
- data/lib/less2sass/less/tree/directive_node.rb +40 -0
- data/lib/less2sass/less/tree/element_node.rb +32 -0
- data/lib/less2sass/less/tree/expression_node.rb +73 -0
- data/lib/less2sass/less/tree/extend_node.rb +14 -0
- data/lib/less2sass/less/tree/import_node.rb +14 -0
- data/lib/less2sass/less/tree/keyword_node.rb +49 -0
- data/lib/less2sass/less/tree/media_node.rb +12 -0
- data/lib/less2sass/less/tree/mixin_call_node.rb +13 -0
- data/lib/less2sass/less/tree/mixin_definition_node.rb +24 -0
- data/lib/less2sass/less/tree/negative_node.rb +9 -0
- data/lib/less2sass/less/tree/node.rb +212 -0
- data/lib/less2sass/less/tree/operation_node.rb +63 -0
- data/lib/less2sass/less/tree/paren_node.rb +9 -0
- data/lib/less2sass/less/tree/quoted_node.rb +64 -0
- data/lib/less2sass/less/tree/rule_node.rb +119 -0
- data/lib/less2sass/less/tree/ruleset_call_node.rb +9 -0
- data/lib/less2sass/less/tree/ruleset_node.rb +82 -0
- data/lib/less2sass/less/tree/selector_node.rb +27 -0
- data/lib/less2sass/less/tree/unicode_descriptor_node.rb +9 -0
- data/lib/less2sass/less/tree/unit_node.rb +17 -0
- data/lib/less2sass/less/tree/url_node.rb +22 -0
- data/lib/less2sass/less/tree/value_node.rb +53 -0
- data/lib/less2sass/less/tree/variable_node.rb +43 -0
- data/lib/less2sass/less/tree.rb +34 -0
- data/lib/less2sass/less.rb +2 -0
- data/lib/less2sass/sass/ast_handler.rb +57 -0
- data/lib/less2sass/sass/parser.rb +20 -0
- data/lib/less2sass/sass.rb +2 -0
- data/lib/less2sass/util.rb +36 -0
- data/lib/less2sass.rb +9 -0
- 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,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,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,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
|