less 1.2.21 → 2.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 (165) hide show
  1. data/.gitignore +4 -3
  2. data/.gitmodules +6 -0
  3. data/Gemfile +3 -0
  4. data/README.md +39 -46
  5. data/Rakefile +5 -50
  6. data/bin/lessc +1 -100
  7. data/less.gemspec +21 -125
  8. data/lib/less.rb +11 -30
  9. data/{LICENSE → lib/less/js/LICENSE} +1 -1
  10. data/lib/less/js/Makefile +56 -0
  11. data/lib/less/js/README.md +20 -0
  12. data/lib/less/js/benchmark/benchmark.less +3979 -0
  13. data/lib/less/js/benchmark/less-benchmark.js +49 -0
  14. data/lib/less/js/bin/lessc +105 -0
  15. data/lib/less/js/build/ecma-5.js +120 -0
  16. data/lib/less/js/build/header.js +7 -0
  17. data/lib/less/js/build/require.js +7 -0
  18. data/lib/less/js/dist/less-1.0.44.js +2655 -0
  19. data/lib/less/js/dist/less-1.1.0.js +2695 -0
  20. data/lib/less/js/dist/less-1.1.0.min.js +16 -0
  21. data/lib/less/js/dist/less-1.1.1.js +2710 -0
  22. data/lib/less/js/dist/less-1.1.1.min.js +16 -0
  23. data/lib/less/js/dist/less-1.1.2.js +2712 -0
  24. data/lib/less/js/dist/less-1.1.2.min.js +16 -0
  25. data/lib/less/js/dist/less-1.1.3.js +2721 -0
  26. data/lib/less/js/dist/less-1.1.3.min.js +16 -0
  27. data/lib/less/js/lib/less/browser.js +369 -0
  28. data/lib/less/js/lib/less/functions.js +174 -0
  29. data/lib/less/js/lib/less/index.js +137 -0
  30. data/lib/less/js/lib/less/parser.js +1098 -0
  31. data/lib/less/js/lib/less/tree.js +13 -0
  32. data/lib/less/js/lib/less/tree/alpha.js +17 -0
  33. data/lib/less/js/lib/less/tree/anonymous.js +13 -0
  34. data/lib/less/js/lib/less/tree/call.js +45 -0
  35. data/lib/less/js/lib/less/tree/color.js +98 -0
  36. data/lib/less/js/lib/less/tree/comment.js +14 -0
  37. data/lib/less/js/lib/less/tree/dimension.js +34 -0
  38. data/lib/less/js/lib/less/tree/directive.js +33 -0
  39. data/lib/less/js/lib/less/tree/element.js +32 -0
  40. data/lib/less/js/lib/less/tree/expression.js +23 -0
  41. data/lib/less/js/lib/less/tree/import.js +77 -0
  42. data/lib/less/js/lib/less/tree/javascript.js +51 -0
  43. data/lib/less/js/lib/less/tree/keyword.js +9 -0
  44. data/lib/less/js/lib/less/tree/mixin.js +106 -0
  45. data/lib/less/js/lib/less/tree/operation.js +32 -0
  46. data/lib/less/js/lib/less/tree/quoted.js +29 -0
  47. data/lib/less/js/lib/less/tree/rule.js +38 -0
  48. data/lib/less/js/lib/less/tree/ruleset.js +179 -0
  49. data/lib/less/js/lib/less/tree/selector.js +28 -0
  50. data/lib/less/js/lib/less/tree/url.js +25 -0
  51. data/lib/less/js/lib/less/tree/value.js +24 -0
  52. data/lib/less/js/lib/less/tree/variable.js +24 -0
  53. data/lib/less/js/package.json +13 -0
  54. data/lib/less/js/test/css/colors.css +42 -0
  55. data/lib/less/js/test/css/comments.css +52 -0
  56. data/lib/less/js/test/css/css-3.css +42 -0
  57. data/lib/less/js/test/css/css-escapes.css +20 -0
  58. data/lib/less/js/test/css/css.css +82 -0
  59. data/lib/less/js/test/css/functions.css +30 -0
  60. data/{spec → lib/less/js/test}/css/import.css +4 -2
  61. data/lib/less/js/test/css/javascript.css +22 -0
  62. data/lib/less/js/test/css/lazy-eval.css +3 -0
  63. data/lib/less/js/test/css/media.css +21 -0
  64. data/lib/less/js/test/css/mixins-args.css +61 -0
  65. data/lib/less/js/test/css/mixins-closure.css +9 -0
  66. data/lib/less/js/test/css/mixins-nested.css +14 -0
  67. data/lib/less/js/test/css/mixins-pattern.css +49 -0
  68. data/lib/less/js/test/css/mixins.css +50 -0
  69. data/{spec → lib/less/js/test}/css/operations.css +20 -2
  70. data/{spec → lib/less/js/test}/css/parens.css +0 -0
  71. data/lib/less/js/test/css/rulesets.css +29 -0
  72. data/{spec → lib/less/js/test}/css/scope.css +6 -2
  73. data/lib/less/js/test/css/selectors.css +32 -0
  74. data/lib/less/js/test/css/strings.css +38 -0
  75. data/lib/less/js/test/css/variables.css +24 -0
  76. data/lib/less/js/test/css/whitespace.css +36 -0
  77. data/lib/less/js/test/less-test.js +75 -0
  78. data/{spec → lib/less/js/test}/less/colors.less +13 -2
  79. data/{spec → lib/less/js/test}/less/comments.less +19 -2
  80. data/{spec → lib/less/js/test}/less/css-3.less +4 -1
  81. data/lib/less/js/test/less/css-escapes.less +28 -0
  82. data/{spec → lib/less/js/test}/less/css.less +10 -18
  83. data/lib/less/js/test/less/functions.less +35 -0
  84. data/{spec → lib/less/js/test}/less/import.less +1 -1
  85. data/{spec → lib/less/js/test}/less/import/import-test-a.less +0 -0
  86. data/{spec → lib/less/js/test}/less/import/import-test-b.less +0 -0
  87. data/{spec → lib/less/js/test}/less/import/import-test-c.less +0 -0
  88. data/{spec → lib/less/js/test}/less/import/import-test-d.css +0 -0
  89. data/lib/less/js/test/less/javascript.less +27 -0
  90. data/{spec → lib/less/js/test}/less/lazy-eval.less +0 -0
  91. data/lib/less/js/test/less/media.less +25 -0
  92. data/lib/less/js/test/less/mixins-args.less +118 -0
  93. data/lib/less/js/test/less/mixins-closure.less +26 -0
  94. data/lib/less/js/test/less/mixins-nested.less +22 -0
  95. data/lib/less/js/test/less/mixins-pattern.less +96 -0
  96. data/{spec → lib/less/js/test}/less/mixins.less +8 -4
  97. data/{spec → lib/less/js/test}/less/operations.less +19 -0
  98. data/{spec → lib/less/js/test}/less/parens.less +0 -0
  99. data/{spec → lib/less/js/test}/less/rulesets.less +2 -2
  100. data/{spec → lib/less/js/test}/less/scope.less +1 -1
  101. data/{spec → lib/less/js/test}/less/selectors.less +1 -1
  102. data/lib/less/js/test/less/strings.less +49 -0
  103. data/lib/less/js/test/less/variables.less +50 -0
  104. data/{spec → lib/less/js/test}/less/whitespace.less +3 -0
  105. data/lib/less/loader.rb +67 -0
  106. data/lib/less/parser.rb +46 -0
  107. data/lib/less/version.rb +3 -0
  108. data/spec/less/one/one.less +1 -0
  109. data/spec/less/parser_spec.rb +30 -0
  110. data/spec/less/two/two.less +1 -0
  111. data/spec/spec_helper.rb +2 -7
  112. metadata +156 -106
  113. data/CHANGELOG +0 -62
  114. data/VERSION +0 -1
  115. data/lib/less/command.rb +0 -110
  116. data/lib/less/engine.rb +0 -52
  117. data/lib/less/engine/grammar/common.tt +0 -29
  118. data/lib/less/engine/grammar/entity.tt +0 -144
  119. data/lib/less/engine/grammar/less.tt +0 -341
  120. data/lib/less/engine/nodes.rb +0 -9
  121. data/lib/less/engine/nodes/element.rb +0 -281
  122. data/lib/less/engine/nodes/entity.rb +0 -79
  123. data/lib/less/engine/nodes/function.rb +0 -93
  124. data/lib/less/engine/nodes/literal.rb +0 -171
  125. data/lib/less/engine/nodes/property.rb +0 -232
  126. data/lib/less/engine/nodes/ruleset.rb +0 -12
  127. data/lib/less/engine/nodes/selector.rb +0 -44
  128. data/lib/less/ext.rb +0 -60
  129. data/spec/command_spec.rb +0 -102
  130. data/spec/css/accessors.css +0 -18
  131. data/spec/css/big.css +0 -3768
  132. data/spec/css/colors.css +0 -14
  133. data/spec/css/comments.css +0 -9
  134. data/spec/css/css-3.css +0 -21
  135. data/spec/css/css.css +0 -50
  136. data/spec/css/dash-prefix.css +0 -12
  137. data/spec/css/functions.css +0 -6
  138. data/spec/css/import-with-extra-paths.css +0 -8
  139. data/spec/css/import-with-partial-in-extra-path.css +0 -6
  140. data/spec/css/lazy-eval.css +0 -1
  141. data/spec/css/mixins-args.css +0 -32
  142. data/spec/css/mixins.css +0 -28
  143. data/spec/css/rulesets.css +0 -17
  144. data/spec/css/selectors.css +0 -13
  145. data/spec/css/strings.css +0 -12
  146. data/spec/css/variables.css +0 -8
  147. data/spec/css/whitespace.css +0 -7
  148. data/spec/engine_spec.rb +0 -127
  149. data/spec/less/accessors.less +0 -20
  150. data/spec/less/big.less +0 -1264
  151. data/spec/less/dash-prefix.less +0 -21
  152. data/spec/less/exceptions/mixed-units-error.less +0 -3
  153. data/spec/less/exceptions/name-error-1.0.less +0 -3
  154. data/spec/less/exceptions/syntax-error-1.0.less +0 -3
  155. data/spec/less/extra_import_path/extra.less +0 -1
  156. data/spec/less/extra_import_path/import/import-test-a.css +0 -1
  157. data/spec/less/extra_import_path/import/import-test-a.less +0 -4
  158. data/spec/less/functions.less +0 -6
  159. data/spec/less/hidden.less +0 -25
  160. data/spec/less/import-with-extra-paths.less +0 -4
  161. data/spec/less/literal-css.less +0 -11
  162. data/spec/less/mixins-args.less +0 -59
  163. data/spec/less/strings.less +0 -14
  164. data/spec/less/variables.less +0 -29
  165. data/spec/spec.css +0 -50
data/CHANGELOG DELETED
@@ -1,62 +0,0 @@
1
- 1.1.6
2
- - hsl() fix
3
- 1.1.5
4
- - rgb() fix
5
- 1.1.4
6
- - support for uppercase ids and classes
7
- - `ex` support
8
- - fixed ruby 1.8 from outputting ascii numbers in the CLI
9
- 1.1.3
10
- - fix to Growl messages
11
- - better benchmark task output
12
- 1.1.2
13
- - full parens support
14
- - don't raise an exception if growlnotify wasn't found
15
- 1.1.1
16
- - added title to Growl notifications
17
- 1.1.0
18
- - added color to command line output
19
- - added Growl support
20
- 1.0.16
21
- - basic support for parens
22
- - support for operations in shorthand properties
23
- 1.0.15
24
- - moved to treetop 1.3.0
25
- - fixed benchmark task
26
- 1.0.14
27
- - support for `*property:` hack
28
- 1.0.13
29
- - importing .css files now works
30
- 1.0.12
31
- - basic selector grouping for better output
32
- - evaluate variables lazily
33
- - support for values starting with `-`
34
- 1.0.11
35
- - ruby 1.8 compatibility fix
36
- 1.0.10
37
- - additional support for css 3
38
- 1.0.9
39
- - overhauled color support & operations
40
- - better handling of css 3 selectors
41
- 1.0.8
42
- - support for rgba
43
- - fixed color expansion
44
- - fixed new-line error in declarations
45
- - fixed attriute selector without element name error
46
- 1.0.6
47
- - fixed grammar for .class#id
48
- - fixed color padding issue
49
- 1.0.5
50
- - added attribute selectors (accessors)
51
- - semi-column at end of ruleset now works
52
- 1.0.4
53
- - removed dependency on polyglot gem
54
- - fixed a moz hack not compiling
55
- 1.0.3
56
- - fixed problem with floats repeating unit twice
57
- 1.0.2
58
- - added support for url() without quotes
59
- 1.0.1
60
- - pulled some patches from jgarber's treetop
61
- 1.0.0
62
- - initial release
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.2.21
data/lib/less/command.rb DELETED
@@ -1,110 +0,0 @@
1
- module Less
2
- class Command
3
- attr_accessor :source, :destination, :options
4
-
5
- def initialize options
6
- $verbose = options[:debug]
7
- @source = options[:source]
8
- @destination = (options[:destination] || options[:source]).gsub /\.(less|lss)/, '.css'
9
- @options = options
10
- @mutter = Mutter.new.clear
11
- end
12
-
13
- def watch?() @options[:watch] end
14
- def compress?() @options[:compress] end
15
- def debug?() @options[:debug] end
16
-
17
- # little function which allows us to
18
- # Ctrl-C exit inside the passed block
19
- def watch
20
- begin
21
- yield
22
- rescue Interrupt
23
- puts
24
- exit 0
25
- end
26
- end
27
-
28
- def run!
29
- if watch?
30
- parse(true) unless File.exist? @destination
31
-
32
- log "Watching for changes in #@source... Ctrl-C to abort.\n: "
33
-
34
- # Main watch loop
35
- loop do
36
- watch { sleep 1 }
37
-
38
- # File has changed
39
- if File.stat( @source ).mtime > File.stat( @destination ).mtime
40
- print Time.now.strftime("%H:%M:%S -- ") if @options[:timestamps]
41
- print "Change detected... "
42
-
43
- # Loop until error is fixed
44
- until parse
45
- log "Press [return] to continue..."
46
- watch { $stdin.gets }
47
- end
48
- end
49
- end
50
- else
51
- parse
52
- end
53
- end
54
-
55
- def parse new = false
56
- begin
57
- # Create a new Less object with the contents of a file
58
- css = Less::Engine.new(File.new(@source), @options).to_css
59
- css = css.delete " \n" if compress?
60
-
61
- File.open( @destination, "w" ) do |file|
62
- file.write css
63
- end
64
-
65
- act, file = (new ? 'Created' : 'Updated'), @destination.split('/').last
66
- print "#{o("* #{act}", :green)} #{file}\n: " if watch?
67
- Growl.notify "#{act} #{file}", :title => 'LESS' if @options[:growl] && @options[:verbose]
68
- rescue Errno::ENOENT => e
69
- abort "#{e}"
70
- rescue SyntaxError => e
71
- err "#{e}\n", "Syntax"
72
- rescue CompileError => e
73
- err "#{e}\n", "Compile"
74
- rescue MixedUnitsError => e
75
- err "`#{e}` you're mixing units together! What do you expect?\n", "Mixed Units"
76
- rescue PathError => e
77
- err "`#{e}` was not found.\n", "Path"
78
- rescue VariableNameError => e
79
- err "#{o(e, :yellow)} is undefined.\n", "Variable Name"
80
- rescue MixinNameError => e
81
- err "#{o(e, :yellow)} is undefined.\n", "Mixin Name"
82
- else
83
- true
84
- end
85
- end
86
-
87
- # Just a logging function to avoid typing '*'
88
- def log s = ''
89
- print '* ' + s.to_s
90
- end
91
-
92
- def err s = '', type = ''
93
- type = type.strip + ' ' unless type.empty?
94
- $stderr.print "#{o("! #{type}Error", :red)}: #{s}"
95
- if @options[:growl]
96
- growl = Growl.new
97
- growl.title = "LESS"
98
- growl.message = "#{type}Error in #@source!"
99
- growl.run
100
- false
101
- end
102
- end
103
-
104
- private
105
-
106
- def o ex, *styles
107
- @mutter.process(ex.to_s, *(@options[:color] ? styles : []))
108
- end
109
- end
110
- end
data/lib/less/engine.rb DELETED
@@ -1,52 +0,0 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'engine/nodes'
4
-
5
- begin
6
- require 'engine/parser'
7
- rescue LoadError
8
- Treetop.load File.join(LESS_GRAMMAR, 'less.tt')
9
- end
10
-
11
- module Less
12
- class Engine
13
- attr_reader :css, :less
14
-
15
- def initialize obj, options = {}
16
- @less = if obj.is_a? File
17
- @path = File.dirname File.expand_path(obj.path)
18
- obj.read
19
- elsif obj.is_a? String
20
- obj.dup
21
- else
22
- raise ArgumentError, "argument must be an instance of File or String!"
23
- end
24
-
25
- @options = options
26
- @parser = StyleSheetParser.new
27
- end
28
-
29
- def parse build = true, env = Node::Element.new
30
- root = @parser.parse(self.prepare)
31
-
32
- return root unless build
33
-
34
- if root
35
- @tree = root.build env.tap {|e| e.file = @path }
36
- else
37
- raise SyntaxError, @parser.failure_message(@options[:color])
38
- end
39
-
40
- @tree
41
- end
42
- alias :to_tree :parse
43
-
44
- def to_css
45
- @css || @css = self.parse.group.to_css
46
- end
47
-
48
- def prepare
49
- @less.gsub(/\r\n/, "\n").gsub(/\t/, ' ')
50
- end
51
- end
52
- end
@@ -1,29 +0,0 @@
1
- module Less
2
- module StyleSheet
3
- grammar Common
4
- #
5
- # Whitespace
6
- #
7
- rule s
8
- [ ]*
9
- end
10
-
11
- rule S
12
- [ ]+
13
- end
14
-
15
- rule ws
16
- [\n ]*
17
- end
18
-
19
- rule WS
20
- [\n ]+
21
- end
22
-
23
- # Non-space char
24
- rule ns
25
- ![ ;,!})\n] .
26
- end
27
- end
28
- end
29
- end
@@ -1,144 +0,0 @@
1
- require 'grammar/common'
2
-
3
- module Less
4
- module StyleSheet
5
- grammar Entity
6
- #
7
- # Entity: Any whitespace delimited token
8
- #
9
- rule entity
10
- url / alpha / function / accessor / keyword / variable / literal / font
11
- end
12
-
13
- rule fonts
14
- font family:(s ',' s font)+ {
15
- def build
16
- Node::FontFamily.new(all.map(&:build))
17
- end
18
-
19
- def all
20
- [font] + family.elements.map {|f| f.font }
21
- end
22
- }
23
- end
24
-
25
- rule font
26
- [a-zA-Z] [-a-zA-Z0-9]* !ns {
27
- def build
28
- Node::Keyword.new(text_value)
29
- end
30
- } / string {
31
- def build
32
- Node::Quoted.new(text_value)
33
- end
34
- }
35
- end
36
-
37
- #
38
- # Tokens which don't need to be evaluated
39
- #
40
- rule literal
41
- color / (dimension / [-a-z]+) '/' dimension {
42
- def build
43
- Node::Anonymous.new(text_value)
44
- end
45
- } / number unit {
46
- def build
47
- Node::Number.new(number.text_value, unit.text_value)
48
- end
49
- } / string {
50
- def build
51
- Node::Quoted.new(text_value)
52
- end
53
- }
54
- end
55
-
56
- #
57
- # `blue`, `small`, `normal` etc.
58
- #
59
- rule keyword
60
- [-a-zA-Z]+ !ns {
61
- def build
62
- Node::Keyword.new(text_value)
63
- end
64
- }
65
- end
66
-
67
- #
68
- # 'hello world' / "hello world"
69
- #
70
- rule string
71
- "'" content:(!"'" . )* "'" {
72
- def value
73
- content.text_value
74
- end
75
- } / ["] content:(!["] . )* ["] {
76
- def value
77
- content.text_value
78
- end
79
- }
80
- end
81
-
82
- #
83
- # Numbers & Units
84
- #
85
- rule dimension
86
- number unit
87
- end
88
-
89
- rule number
90
- '-'? [0-9]* '.' [0-9]+ / '-'? [0-9]+
91
- end
92
-
93
- rule unit
94
- ('px'/'em'/'pc'/'%'/'ex'/'in'/'deg'/'s'/'pt'/'cm'/'mm')?
95
- end
96
-
97
- #
98
- # Color
99
- #
100
- rule color
101
- '#' rgb {
102
- def build
103
- Node::Color.new(*rgb.build)
104
- end
105
- } / fn:(('hsl'/'rgb') 'a'?) arguments {
106
- def build
107
- Node::Function.new(fn.text_value, arguments.build.flatten)
108
- end
109
- }
110
- end
111
-
112
- #
113
- # 00ffdd / 0fd
114
- #
115
- rule rgb
116
- r:(hex hex) g:(hex hex) b:(hex hex) {
117
- def build
118
- [r.text_value, g.text_value, b.text_value]
119
- end
120
- } / r:hex g:hex b:hex {
121
- def build
122
- [r.text_value, g.text_value, b.text_value].map {|c| c * 2 }
123
- end
124
- }
125
- end
126
-
127
- rule hex
128
- [a-fA-F0-9]
129
- end
130
-
131
- #
132
- # Special case for IE alpha filter
133
- #
134
- rule alpha
135
- "alpha" '(' "opacity=" variable ')' {
136
- def build env
137
- var = variable.text_value
138
- Node::Quoted.new(text_value.sub(var, env.nearest(var).evaluate.to_i.to_s))
139
- end
140
- }
141
- end
142
- end
143
- end
144
- end
@@ -1,341 +0,0 @@
1
- require 'grammar/common'
2
- require 'grammar/entity'
3
-
4
- module Less
5
- grammar StyleSheet
6
- include Common
7
- include Entity
8
-
9
- rule primary
10
- (import / declaration / ruleset / mixin / comment)* {
11
- def build env = Less::Element.new
12
- elements.map do |e|
13
- e.build env if e.respond_to? :build
14
- end; env
15
- end
16
- }
17
- end
18
-
19
- rule comment
20
- ws '/*' (!'*/' . )* '*/' ws / ws '//' (!"\n" .)* "\n" ws
21
- end
22
-
23
- #
24
- # div, .class, body > p {...}
25
- #
26
- rule ruleset
27
- selectors "{" ws primary ws "}" s hide:(';'?) ws {
28
- def build env
29
- # Build the ruleset for each selector
30
- selectors.build(env, :ruleset).each do |sel|
31
- sel.hide unless hide.empty?
32
- primary.build sel
33
- end
34
- end
35
- # Mixin Declaration
36
- } / ws '.' name:[-a-zA-Z0-9_]+ ws parameters ws "{" ws primary ws "}" ws {
37
- def build env
38
- env << Node::Mixin::Def.new(name.text_value, parameters.build(env))
39
- primary.build env.last
40
- end
41
- }
42
- end
43
-
44
- rule mixin
45
- name:('.' [-a-zA-Z0-9_]+) args:(arguments) s ';' ws {
46
- def build env
47
- definition = env.nearest(name.text_value, :mixin) or raise MixinNameError, "#{name.text_value}() in #{env}"
48
- params = args.build.map {|i| Node::Expression.new i } unless args.empty?
49
- env << Node::Mixin::Call.new(definition, params || [], env)
50
- end
51
- } / ws selectors ';' ws {
52
- def build env
53
- selectors.build(env, :mixin).each do |path|
54
- rules = path.inject(env.root) do |current, node|
55
- current.descend(node.selector, node) or raise MixinNameError, "#{selectors.text_value} in #{env}"
56
- end.rules
57
- env.rules += rules
58
- end
59
- end
60
- }
61
- end
62
-
63
- rule selectors
64
- ws selector tail:(s ',' ws selector)* ws {
65
- def build env, method
66
- all.map do |e|
67
- e.send(method, env) if e.respond_to? method
68
- end.compact
69
- end
70
-
71
- def all
72
- [selector] + tail.elements.map {|e| e.selector }
73
- end
74
- }
75
- end
76
-
77
- #
78
- # div > p a {...}
79
- #
80
- rule selector
81
- sel:(s select element s)+ '' {
82
- def ruleset env
83
- sel.elements.inject(env) do |node, e|
84
- node << Node::Element.new(e.element.text_value, e.select.text_value)
85
- node.last
86
- end
87
- end
88
-
89
- def mixin env
90
- sel.elements.map do |e|
91
- Node::Element.new(e.element.text_value, e.select.text_value)
92
- end
93
- end
94
- }
95
- end
96
-
97
- rule parameters
98
- '(' s ')' {
99
- def build env
100
- []
101
- end
102
- } / '(' parameter tail:(s ',' s parameter)* ')' {
103
- def build env
104
- all.map do |e|
105
- e.build(env)
106
- end
107
- end
108
-
109
- def all
110
- [parameter] + tail.elements.map {|e| e.parameter }
111
- end
112
- }
113
- end
114
-
115
- rule parameter
116
- variable s ':' s expressions {
117
- def build env
118
- Node::Variable.new(variable.text_value, expressions.build(env), env)
119
- end
120
- }
121
- end
122
-
123
- rule import
124
- ws "@import" S url:(string / url) medias? s ';' ws {
125
- def build env
126
- standard_path = File.join(env.root.file || Dir.pwd, url.value)
127
-
128
- # Compile a list of possible paths for this file
129
- paths = $LESS_LOAD_PATH.map { |p| File.join(p, url.value) } + [standard_path]
130
- # Standardize and make uniq
131
- paths = paths.map do |p|
132
- p = File.expand_path(p)
133
- p += '.less' unless p =~ /\.(le|c)ss$/
134
- p
135
- end.uniq
136
-
137
- # Use the first that exists if any
138
- if path = paths.detect {|p| File.exists?(p)}
139
- unless env.root.imported.include?(path)
140
- env.root.imported << path
141
- env.rules += Less::Engine.new(File.new(path)).to_tree.rules
142
- end
143
- else
144
- raise ImportError, standard_path
145
- end
146
-
147
- end
148
- }
149
- end
150
-
151
- rule url
152
- 'url(' path:(string / [-a-zA-Z0-9_%$/.&=:;#+?]+) ')' {
153
- def build env = nil
154
- Node::Function.new('url', value)
155
- end
156
-
157
- def value
158
- Node::Quoted.new CGI.unescape(path.text_value)
159
- end
160
- }
161
- end
162
-
163
- rule medias
164
- [-a-z]+ (s ',' s [a-z]+)*
165
- end
166
-
167
- #
168
- # @my-var: 12px;
169
- # height: 100%;
170
- #
171
- rule declaration
172
- ws name:(ident / variable) s ':' ws expressions tail:(ws ',' ws expressions)* s (';'/ ws &'}') ws {
173
- def build env
174
- result = all.map {|e| e.build(env) if e.respond_to? :build }.compact
175
- env << (name.text_value =~ /^@/ ?
176
- Node::Variable : Node::Property).new(name.text_value, result, env)
177
- end
178
-
179
- def all
180
- [expressions] + tail.elements.map {|f| f.expressions }
181
- end
182
- # Empty rule
183
- } / ws ident s ':' s ';' ws
184
- end
185
-
186
- #
187
- # An operation or compound value
188
- #
189
- rule expressions
190
- # Operation
191
- expression tail:(operator expression)+ {
192
- def build env = nil
193
- all.map {|e| e.build(env) }.dissolve
194
- end
195
-
196
- def all
197
- [expression] + tail.elements.map {|i| [i.operator, i.expression] }.flatten.compact
198
- end
199
- # Space-delimited expressions
200
- } / expression tail:(WS expression)* i:important? {
201
- def build env = nil
202
- all.map {|e| e.build(env) if e.respond_to? :build }.compact
203
- end
204
-
205
- def all
206
- [expression] + tail.elements.map {|f| f.expression } + [i]
207
- end
208
- # Catch-all rule
209
- } / [-a-zA-Z0-9_.&*/=:,+? \[\]()#%]+ {
210
- def build env
211
- [Node::Anonymous.new(text_value)]
212
- end
213
- }
214
- end
215
-
216
- rule expression
217
- '(' s expressions s ')' {
218
- def build env = nil
219
- Node::Expression.new(['('] + expressions.build(env).flatten + [')'])
220
- end
221
- } / entity '' {
222
- def build env = nil
223
- e = entity.method(:build).arity.zero?? entity.build : entity.build(env)
224
- e.respond_to?(:dissolve) ? e.dissolve : e
225
- end
226
- }
227
- end
228
-
229
- # !important
230
- rule important
231
- s '!' s 'important' {
232
- def build env = nil
233
- Node::Keyword.new(text_value.strip)
234
- end
235
- }
236
- end
237
-
238
- #
239
- # An identifier
240
- #
241
- rule ident
242
- '*'? '-'? [-a-z_] [-a-z0-9_]*
243
- end
244
-
245
- rule variable
246
- '@' [-a-zA-Z0-9_]+ {
247
- def build
248
- Node::Variable.new(text_value)
249
- end
250
- }
251
- end
252
-
253
- #
254
- # div / .class / #id / input[type="text"] / lang(fr)
255
- #
256
- rule element
257
- ((class / id / tag / ident) attribute* ('(' [a-zA-Z]+ ')' / '(' (pseudo_exp / selector / [0-9]+) ')' )?)+
258
- / attribute+ / '@media' / '@font-face'
259
- end
260
-
261
- #
262
- # 4n+1
263
- #
264
- rule pseudo_exp
265
- '-'? ([0-9]+)? 'n' ([-+] [0-9]+)?
266
- end
267
-
268
- #
269
- # [type="text"]
270
- #
271
- rule attribute
272
- '[' tag ([|~*$^]? '=') (string / [-a-zA-Z_0-9]+) ']' / '[' (tag / string) ']'
273
- end
274
-
275
- rule class
276
- '.' [_a-zA-Z] [-a-zA-Z0-9_]*
277
- end
278
-
279
- rule id
280
- '#' [_a-zA-Z] [-a-zA-Z0-9_]*
281
- end
282
-
283
- rule tag
284
- [a-zA-Z] [-a-zA-Z]* [0-9]? / '*'
285
- end
286
-
287
- rule select
288
- (s [+>~] s / '::' / s ':' / S)?
289
- end
290
-
291
- # TODO: Merge this with attribute rule
292
- rule accessor
293
- ident:(class / id / tag) '[' attr:(string / variable) ']' {
294
- def build env
295
- env.nearest(ident.text_value)[attr.text_value.delete(%q["'])].evaluate
296
- end
297
- }
298
- end
299
-
300
- rule operator
301
- S [-+*/] S {
302
- def build env
303
- Node::Operator.new(text_value.strip)
304
- end
305
- } / [-+*/] {
306
- def build env
307
- Node::Operator.new(text_value)
308
- end
309
- }
310
- end
311
-
312
- #
313
- # Functions and arguments
314
- #
315
- rule function
316
- name:([-a-zA-Z_]+) arguments {
317
- def build
318
- Node::Function.new(name.text_value, arguments.build)
319
- end
320
- }
321
- end
322
-
323
- rule arguments
324
- '(' s expressions s tail:(',' s expressions s)* ')' {
325
- def build
326
- all.map do |e|
327
- e.build if e.respond_to? :build
328
- end.compact
329
- end
330
-
331
- def all
332
- [expressions] + tail.elements.map {|e| e.expressions }
333
- end
334
- } / '(' s ')' {
335
- def build
336
- []
337
- end
338
- }
339
- end
340
- end
341
- end