less 1.2.21 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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