less 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/lib/less/js/.gitignore +7 -0
  3. data/lib/less/js/.npmignore +1 -0
  4. data/lib/less/js/CHANGELOG.md +118 -0
  5. data/lib/less/js/CONTRIBUTING.md +50 -0
  6. data/lib/less/js/Makefile +14 -2
  7. data/lib/less/js/bin/lessc +72 -21
  8. data/lib/less/js/dist/less-1.3.1.js +4011 -0
  9. data/lib/less/js/dist/less-1.3.1.min.js +9 -0
  10. data/lib/less/js/dist/less-1.3.2.js +4401 -0
  11. data/lib/less/js/dist/less-1.3.2.min.js +9 -0
  12. data/lib/less/js/dist/less-1.3.3.js +4413 -0
  13. data/lib/less/js/dist/less-1.3.3.min.js +9 -0
  14. data/lib/less/js/dist/less-rhino-1.3.1.js +3725 -0
  15. data/lib/less/js/dist/less-rhino-1.3.2.js +3990 -0
  16. data/lib/less/js/dist/less-rhino-1.3.3.js +4002 -0
  17. data/lib/less/js/lib/less/browser.js +192 -53
  18. data/lib/less/js/lib/less/colors.js +1 -0
  19. data/lib/less/js/lib/less/functions.js +159 -10
  20. data/lib/less/js/lib/less/index.js +124 -56
  21. data/lib/less/js/lib/less/lessc_helper.js +62 -0
  22. data/lib/less/js/lib/less/parser.js +352 -135
  23. data/lib/less/js/lib/less/rhino.js +84 -23
  24. data/lib/less/js/lib/less/tree.js +28 -0
  25. data/lib/less/js/lib/less/tree/anonymous.js +15 -1
  26. data/lib/less/js/lib/less/tree/assignment.js +3 -1
  27. data/lib/less/js/lib/less/tree/call.js +12 -6
  28. data/lib/less/js/lib/less/tree/color.js +10 -0
  29. data/lib/less/js/lib/less/tree/dimension.js +3 -1
  30. data/lib/less/js/lib/less/tree/directive.js +9 -5
  31. data/lib/less/js/lib/less/tree/element.js +8 -6
  32. data/lib/less/js/lib/less/tree/import.js +16 -13
  33. data/lib/less/js/lib/less/tree/media.js +16 -9
  34. data/lib/less/js/lib/less/tree/mixin.js +123 -46
  35. data/lib/less/js/lib/less/tree/operation.js +5 -0
  36. data/lib/less/js/lib/less/tree/quoted.js +15 -1
  37. data/lib/less/js/lib/less/tree/ratio.js +13 -0
  38. data/lib/less/js/lib/less/tree/rule.js +7 -0
  39. data/lib/less/js/lib/less/tree/ruleset.js +232 -34
  40. data/lib/less/js/lib/less/tree/selector.js +21 -11
  41. data/lib/less/js/lib/less/tree/unicode-descriptor.js +13 -0
  42. data/lib/less/js/lib/less/tree/url.js +16 -14
  43. data/lib/less/js/lib/less/tree/variable.js +13 -1
  44. data/lib/less/js/package.json +13 -3
  45. data/lib/less/js/test/browser-test-prepare.js +29 -0
  46. data/lib/less/js/test/browser/common.js +74 -0
  47. data/lib/less/js/test/browser/css/relative-urls/urls.css +36 -0
  48. data/lib/less/js/test/browser/css/rootpath-relative/urls.css +36 -0
  49. data/lib/less/js/test/browser/css/rootpath/urls.css +36 -0
  50. data/lib/less/js/test/browser/css/urls.css +36 -0
  51. data/lib/less/js/test/browser/jasmine-html.js +681 -0
  52. data/lib/less/js/test/browser/jasmine.css +82 -0
  53. data/lib/less/js/test/browser/jasmine.js +2600 -0
  54. data/lib/less/js/test/browser/less/imports/urls.less +4 -0
  55. data/lib/less/js/test/browser/less/imports/urls2.less +4 -0
  56. data/lib/less/js/test/browser/less/relative-urls/urls.less +33 -0
  57. data/lib/less/js/test/browser/less/rootpath-relative/urls.less +33 -0
  58. data/lib/less/js/test/browser/less/rootpath/urls.less +33 -0
  59. data/lib/less/js/test/browser/less/urls.less +33 -0
  60. data/lib/less/js/test/browser/phantom-runner.js +139 -0
  61. data/lib/less/js/test/browser/runner-browser.js +3 -0
  62. data/lib/less/js/test/browser/runner-main.js +15 -0
  63. data/lib/less/js/test/browser/runner-relative-urls.js +4 -0
  64. data/lib/less/js/test/browser/runner-rootpath-relative.js +5 -0
  65. data/lib/less/js/test/browser/runner-rootpath.js +4 -0
  66. data/lib/less/js/test/browser/template.htm +10 -0
  67. data/lib/less/js/test/css/charsets.css +1 -0
  68. data/lib/less/js/test/css/colors.css +22 -0
  69. data/lib/less/js/test/css/comments.css +7 -0
  70. data/lib/less/js/test/css/css-3.css +57 -2
  71. data/lib/less/js/test/css/css-escapes.css +4 -0
  72. data/lib/less/js/test/css/css.css +11 -11
  73. data/lib/less/js/test/css/debug/linenumbers-all.css +43 -0
  74. data/lib/less/js/test/css/debug/linenumbers-comments.css +35 -0
  75. data/lib/less/js/test/css/debug/linenumbers-mediaquery.css +35 -0
  76. data/lib/less/js/test/css/functions.css +59 -2
  77. data/lib/less/js/test/css/ie-filters.css +7 -3
  78. data/lib/less/js/test/css/import-once.css +3 -0
  79. data/lib/less/js/test/css/import.css +7 -9
  80. data/lib/less/js/test/css/javascript.css +3 -2
  81. data/lib/less/js/test/css/media.css +116 -0
  82. data/lib/less/js/test/css/mixins-args.css +23 -4
  83. data/lib/less/js/test/css/mixins-guards.css +13 -0
  84. data/lib/less/js/test/css/mixins-important.css +21 -0
  85. data/lib/less/js/test/css/mixins-named-args.css +27 -0
  86. data/lib/less/js/test/css/mixins.css +50 -0
  87. data/lib/less/js/test/css/scope.css +20 -0
  88. data/lib/less/js/test/css/selectors.css +64 -0
  89. data/lib/less/js/test/css/static-urls/urls.css +42 -0
  90. data/lib/less/js/test/css/strings.css +2 -2
  91. data/lib/less/js/test/css/urls.css +42 -0
  92. data/lib/less/js/test/css/variables.css +0 -1
  93. data/lib/less/js/test/css/whitespace.css +4 -0
  94. data/lib/less/js/test/less-test.js +145 -36
  95. data/lib/less/js/test/less/charsets.less +3 -0
  96. data/lib/less/js/test/less/colors.less +27 -0
  97. data/lib/less/js/test/less/comments.less +12 -0
  98. data/lib/less/js/test/less/css-3.less +54 -6
  99. data/lib/less/js/test/less/css-escapes.less +6 -1
  100. data/lib/less/js/test/less/css.less +14 -12
  101. data/lib/less/js/test/less/debug/import/test.less +25 -0
  102. data/lib/less/js/test/less/debug/linenumbers.less +23 -0
  103. data/lib/less/js/test/less/errors/bad-variable-declaration1.less +1 -0
  104. data/lib/less/js/test/less/errors/bad-variable-declaration1.txt +2 -0
  105. data/lib/less/js/test/less/errors/comment-in-selector.less +1 -0
  106. data/lib/less/js/test/less/errors/comment-in-selector.txt +2 -0
  107. data/lib/less/js/test/less/errors/import-missing.less +1 -0
  108. data/lib/less/js/test/less/errors/import-missing.txt +3 -0
  109. data/lib/less/js/test/less/errors/import-no-semi.less +1 -0
  110. data/lib/less/js/test/less/errors/import-no-semi.txt +2 -0
  111. data/lib/less/js/test/less/errors/import-subfolder1.less +1 -0
  112. data/lib/less/js/test/less/errors/import-subfolder1.txt +3 -0
  113. data/lib/less/js/test/less/errors/import-subfolder2.less +1 -0
  114. data/lib/less/js/test/less/errors/import-subfolder2.txt +2 -0
  115. data/lib/less/js/test/less/errors/imports/import-subfolder1.less +1 -0
  116. data/lib/less/js/test/less/errors/imports/import-subfolder2.less +1 -0
  117. data/lib/less/js/test/less/errors/imports/import-test.less +4 -0
  118. data/lib/less/js/test/less/errors/imports/subfolder/mixin-not-defined.less +1 -0
  119. data/lib/less/js/test/less/errors/imports/subfolder/parse-error-curly-bracket.less +1 -0
  120. data/lib/less/js/test/less/errors/javascript-error.less +3 -0
  121. data/lib/less/js/test/less/errors/javascript-error.txt +4 -0
  122. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-1.less +6 -0
  123. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-1.txt +4 -0
  124. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-2.less +6 -0
  125. data/lib/less/js/test/less/errors/mixed-mixin-definition-args-2.txt +4 -0
  126. data/lib/less/js/test/less/errors/mixin-not-defined.less +11 -0
  127. data/lib/less/js/test/less/errors/mixin-not-defined.txt +3 -0
  128. data/lib/less/js/test/less/errors/mixin-not-matched.less +6 -0
  129. data/lib/less/js/test/less/errors/mixin-not-matched.txt +3 -0
  130. data/lib/less/js/test/less/errors/mixin-not-matched2.less +6 -0
  131. data/lib/less/js/test/less/errors/mixin-not-matched2.txt +3 -0
  132. data/lib/less/js/test/less/errors/parse-error-curly-bracket.less +1 -0
  133. data/lib/less/js/test/less/errors/parse-error-curly-bracket.txt +2 -0
  134. data/lib/less/js/test/less/errors/parse-error-missing-bracket.less +2 -0
  135. data/lib/less/js/test/less/errors/parse-error-missing-bracket.txt +2 -0
  136. data/lib/less/js/test/less/errors/parse-error-with-import.less +13 -0
  137. data/lib/less/js/test/less/errors/parse-error-with-import.txt +4 -0
  138. data/lib/less/js/test/less/errors/property-ie5-hack.less +3 -0
  139. data/lib/less/js/test/less/errors/property-ie5-hack.txt +4 -0
  140. data/lib/less/js/test/less/errors/recursive-variable.less +1 -0
  141. data/lib/less/js/test/less/errors/recursive-variable.txt +2 -0
  142. data/lib/less/js/test/less/functions.less +64 -2
  143. data/lib/less/js/test/less/ie-filters.less +7 -0
  144. data/lib/less/js/test/less/import-once.less +4 -0
  145. data/lib/less/js/test/less/import.less +2 -1
  146. data/lib/less/js/test/less/import/deeper/import-once-test-a.less +1 -0
  147. data/lib/less/js/test/less/import/import-and-relative-paths-test.less +6 -0
  148. data/lib/less/js/test/less/import/import-charset-test.less +1 -0
  149. data/lib/less/js/test/less/import/import-once-test-c.less +6 -0
  150. data/lib/less/js/test/less/import/import-test-a.less +1 -0
  151. data/lib/less/js/test/less/import/import-test-c.less +0 -1
  152. data/lib/less/js/test/less/import/imports/font.less +8 -0
  153. data/lib/less/js/test/less/import/imports/logo.less +5 -0
  154. data/lib/less/js/test/less/import/urls.less +1 -0
  155. data/lib/less/js/test/less/javascript.less +4 -2
  156. data/lib/less/js/test/less/media.less +120 -0
  157. data/lib/less/js/test/less/mixins-args.less +40 -10
  158. data/lib/less/js/test/less/mixins-guards.less +30 -0
  159. data/lib/less/js/test/less/mixins-important.less +4 -0
  160. data/lib/less/js/test/less/mixins-named-args.less +36 -0
  161. data/lib/less/js/test/less/mixins.less +47 -0
  162. data/lib/less/js/test/less/scope.less +48 -1
  163. data/lib/less/js/test/less/selectors.less +81 -0
  164. data/lib/less/js/test/less/static-urls/urls.less +33 -0
  165. data/lib/less/js/test/less/strings.less +1 -1
  166. data/lib/less/js/test/less/urls.less +33 -0
  167. data/lib/less/js/test/less/variables.less +0 -1
  168. data/lib/less/js/test/less/whitespace.less +7 -0
  169. data/lib/less/version.rb +1 -1
  170. metadata +101 -4
  171. data/lib/less/js/CHANGELOG +0 -41
  172. data/lib/less/js/lib/less/cssmin.js +0 -355
@@ -1,9 +1,11 @@
1
1
  var path = require('path'),
2
2
  sys = require('util'),
3
+ url = require('url'),
4
+ http = require('http'),
3
5
  fs = require('fs');
4
6
 
5
7
  var less = {
6
- version: [1, 3, 0],
8
+ version: [1, 3, 3],
7
9
  Parser: require('./parser').Parser,
8
10
  importer: require('./parser').importer,
9
11
  tree: require('./tree'),
@@ -33,20 +35,19 @@ var less = {
33
35
  return ee;
34
36
  }
35
37
  },
36
- writeError: function (ctx, options) {
38
+ formatError: function(ctx, options) {
37
39
  options = options || {};
38
40
 
39
41
  var message = "";
40
42
  var extract = ctx.extract;
41
43
  var error = [];
42
- var stylize = options.color ? less.stylize : function (str) { return str };
43
-
44
- if (options.silent) { return }
44
+ var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str };
45
45
 
46
- if (ctx.stack) { return sys.error(stylize(ctx.stack, 'red')) }
46
+ // only output a stack if it isn't a less error
47
+ if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red') }
47
48
 
48
- if (!ctx.hasOwnProperty('index')) {
49
- return sys.error(ctx.stack || ctx.message);
49
+ if (!ctx.hasOwnProperty('index') || !extract) {
50
+ return ctx.stack || ctx.message;
50
51
  }
51
52
 
52
53
  if (typeof(extract[0]) === 'string') {
@@ -62,18 +63,25 @@ var less = {
62
63
  if (typeof(extract[2]) === 'string') {
63
64
  error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
64
65
  }
65
- error = error.join('\n') + '\033[0m\n';
66
+ error = error.join('\n') + stylize('', 'reset') + '\n';
66
67
 
67
68
  message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
68
69
  ctx.filename && (message += stylize(' in ', 'red') + ctx.filename +
69
70
  stylize(':' + ctx.line + ':' + ctx.column, 'grey'));
70
71
 
71
- sys.error(message, error);
72
+ message += '\n' + error;
72
73
 
73
74
  if (ctx.callLine) {
74
- sys.error(stylize('from ', 'red') + (ctx.filename || ''));
75
- sys.error(stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract);
75
+ message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
76
+ message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
76
77
  }
78
+
79
+ return message;
80
+ },
81
+ writeError: function (ctx, options) {
82
+ options = options || {};
83
+ if (options.silent) { return }
84
+ sys.error(less.formatError(ctx, options));
77
85
  }
78
86
  };
79
87
 
@@ -83,44 +91,121 @@ var less = {
83
91
  'call', 'url', 'alpha', 'import',
84
92
  'mixin', 'comment', 'anonymous', 'value',
85
93
  'javascript', 'assignment', 'condition', 'paren',
86
- 'media'
94
+ 'media', 'ratio', 'unicode-descriptor'
87
95
  ].forEach(function (n) {
88
96
  require('./tree/' + n);
89
97
  });
90
98
 
99
+
100
+ var isUrlRe = /^(?:https?:)?\/\//i;
101
+
91
102
  less.Parser.importer = function (file, paths, callback, env) {
92
- var pathname;
93
-
94
- // TODO: Undo this at some point,
95
- // or use different approach.
96
- paths.unshift('.');
97
-
98
- for (var i = 0; i < paths.length; i++) {
99
- try {
100
- pathname = path.join(paths[i], file);
101
- fs.statSync(pathname);
102
- break;
103
- } catch (e) {
104
- pathname = null;
103
+ var pathname, dirname, data;
104
+
105
+ function parseFile(e, data) {
106
+ if (e) return callback(e);
107
+
108
+ var rootpath = env.rootpath,
109
+ j = file.lastIndexOf('/');
110
+
111
+ // Pass on an updated rootpath if path of imported file is relative and file
112
+ // is in a (sub|sup) directory
113
+ //
114
+ // Examples:
115
+ // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
116
+ // then rootpath should become 'less/module/nav/'
117
+ // - If path of imported file is '../mixins.less' and rootpath is 'less/',
118
+ // then rootpath should become 'less/../'
119
+ if(env.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
120
+ rootpath = rootpath + file.slice(0, j+1); // append (sub|sup) directory path of imported file
105
121
  }
106
- }
107
-
108
- if (pathname) {
109
- fs.readFile(pathname, 'utf-8', function(e, data) {
110
- if (e) return callback(e);
111
122
 
112
- new(less.Parser)({
113
- paths: [path.dirname(pathname)].concat(paths),
114
- filename: pathname
115
- }).parse(data, function (e, root) {
116
- callback(e, root, data);
123
+ env.contents[pathname] = data; // Updating top importing parser content cache.
124
+ new(less.Parser)({
125
+ paths: [dirname].concat(paths),
126
+ filename: pathname,
127
+ contents: env.contents,
128
+ files: env.files,
129
+ syncImport: env.syncImport,
130
+ relativeUrls: env.relativeUrls,
131
+ rootpath: rootpath,
132
+ dumpLineNumbers: env.dumpLineNumbers
133
+ }).parse(data, function (e, root) {
134
+ callback(e, root, pathname);
135
+ });
136
+ };
137
+
138
+ var isUrl = isUrlRe.test( file );
139
+ if (isUrl || isUrlRe.test(paths[0])) {
140
+
141
+ var urlStr = isUrl ? file : url.resolve(paths[0], file),
142
+ urlObj = url.parse(urlStr),
143
+ req = {
144
+ host: urlObj.hostname,
145
+ port: urlObj.port || 80,
146
+ path: urlObj.pathname + (urlObj.search||'')
147
+ };
148
+
149
+ http.get(req, function (res) {
150
+ var body = '';
151
+ res.on('data', function (chunk) {
152
+ body += chunk.toString();
153
+ });
154
+ res.on('end', function () {
155
+ if (res.statusCode === 404) {
156
+ callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
157
+ }
158
+ if (!body) {
159
+ sys.error( 'Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"' );
160
+ }
161
+ pathname = urlStr;
162
+ dirname = urlObj.protocol +'//'+ urlObj.host + urlObj.pathname.replace(/[^\/]*$/, '');
163
+ parseFile(null, body);
117
164
  });
165
+ }).on('error', function (err) {
166
+ callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ err +"\n" });
118
167
  });
168
+
119
169
  } else {
120
- if (typeof(env.errback) === "function") {
121
- env.errback(file, paths, callback);
170
+
171
+ // TODO: Undo this at some point,
172
+ // or use different approach.
173
+ var paths = [].concat(paths);
174
+ paths.push('.');
175
+
176
+ for (var i = 0; i < paths.length; i++) {
177
+ try {
178
+ pathname = path.join(paths[i], file);
179
+ fs.statSync(pathname);
180
+ break;
181
+ } catch (e) {
182
+ pathname = null;
183
+ }
184
+ }
185
+
186
+ paths = paths.slice(0, paths.length - 1);
187
+
188
+ if (!pathname) {
189
+
190
+ if (typeof(env.errback) === "function") {
191
+ env.errback(file, paths, callback);
192
+ } else {
193
+ callback({ type: 'File', message: "'" + file + "' wasn't found.\n" });
194
+ }
195
+ return;
196
+ }
197
+
198
+ dirname = path.dirname(pathname);
199
+
200
+ if (env.syncImport) {
201
+ try {
202
+ data = fs.readFileSync(pathname, 'utf-8');
203
+ parseFile(null, data);
204
+ } catch (e) {
205
+ parseFile(e);
206
+ }
122
207
  } else {
123
- callback({ type: 'File', message: "'" + file + "' wasn't found.\n" });
208
+ fs.readFile(pathname, 'utf-8', parseFile);
124
209
  }
125
210
  }
126
211
  }
@@ -129,20 +214,3 @@ require('./functions');
129
214
  require('./colors');
130
215
 
131
216
  for (var k in less) { exports[k] = less[k] }
132
-
133
- // Stylize a string
134
- function stylize(str, style) {
135
- var styles = {
136
- 'bold' : [1, 22],
137
- 'inverse' : [7, 27],
138
- 'underline' : [4, 24],
139
- 'yellow' : [33, 39],
140
- 'green' : [32, 39],
141
- 'red' : [31, 39],
142
- 'grey' : [90, 39]
143
- };
144
- return '\033[' + styles[style][0] + 'm' + str +
145
- '\033[' + styles[style][1] + 'm';
146
- }
147
- less.stylize = stylize;
148
-
@@ -0,0 +1,62 @@
1
+ // lessc_helper.js
2
+ //
3
+ // helper functions for lessc
4
+ sys = require('util');
5
+
6
+ var lessc_helper = {
7
+
8
+ //Stylize a string
9
+ stylize : function(str, style) {
10
+ var styles = {
11
+ 'reset' : [0, 0],
12
+ 'bold' : [1, 22],
13
+ 'inverse' : [7, 27],
14
+ 'underline' : [4, 24],
15
+ 'yellow' : [33, 39],
16
+ 'green' : [32, 39],
17
+ 'red' : [31, 39],
18
+ 'grey' : [90, 39]
19
+ };
20
+ return '\033[' + styles[style][0] + 'm' + str +
21
+ '\033[' + styles[style][1] + 'm';
22
+ },
23
+
24
+ //Print command line options
25
+ printUsage: function() {
26
+ sys.puts("usage: lessc [option option=parameter ...] <source> [destination]");
27
+ sys.puts("");
28
+ sys.puts("If source is set to `-' (dash or hyphen-minus), input is read from stdin.");
29
+ sys.puts("");
30
+ sys.puts("options:");
31
+ sys.puts(" -h, --help Print help (this message) and exit.");
32
+ sys.puts(" --include-path Set include paths. Separated by `:'. Use `;' on Windows.");
33
+ sys.puts(" --no-color Disable colorized output.");
34
+ sys.puts(" -s, --silent Suppress output of error messages.");
35
+ sys.puts(" --strict-imports Force evaluation of imports.");
36
+ sys.puts(" --verbose Be verbose.");
37
+ sys.puts(" -v, --version Print version number and exit.");
38
+ sys.puts(" -x, --compress Compress output by removing some whitespaces.");
39
+ sys.puts(" --yui-compress Compress output using ycssmin");
40
+ sys.puts(" -O0, -O1, -O2 Set the parser's optimization level. The lower");
41
+ sys.puts(" the number, the less nodes it will create in the");
42
+ sys.puts(" tree. This could matter for debugging, or if you");
43
+ sys.puts(" want to access the individual nodes in the tree.");
44
+ sys.puts(" --line-numbers=TYPE Outputs filename and line numbers.");
45
+ sys.puts(" TYPE can be either 'comments', which will output");
46
+ sys.puts(" the debug info within comments, 'mediaquery'");
47
+ sys.puts(" that will output the information within a fake");
48
+ sys.puts(" media query which is compatible with the SASS");
49
+ sys.puts(" format, and 'all' which will do both.");
50
+ sys.puts(" -rp, --rootpath Set rootpath for url rewriting in relative imports and urls.");
51
+ sys.puts(" Works with or withour the relative-urls option.");
52
+ sys.puts(" -ru, --relative-urls re-write relative urls to the base less file.");
53
+ sys.puts("");
54
+ sys.puts("Report bugs to: http://github.com/cloudhead/less.js/issues");
55
+ sys.puts("Home page: <http://lesscss.org/>");
56
+ }
57
+
58
+
59
+ }
60
+
61
+ // Exports helper functions
62
+ for (var h in lessc_helper) { exports[h] = lessc_helper[h] }
@@ -1,4 +1,4 @@
1
- var less, tree;
1
+ var less, tree, charset;
2
2
 
3
3
  if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
4
4
  // Rhino
@@ -65,17 +65,25 @@ less.Parser = function Parser(env) {
65
65
 
66
66
  var that = this;
67
67
 
68
+ // Top parser on an import tree must be sure there is one "env"
69
+ // which will then be passed arround by reference.
70
+ var env = env || { };
71
+ // env.contents and files must be passed arround with top env
72
+ if (!env.contents) { env.contents = {}; }
73
+ env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided
74
+ if (!env.files) { env.files = {}; }
75
+
68
76
  // This function is called after all files
69
77
  // have been imported through `@import`.
70
78
  var finish = function () {};
71
79
 
72
80
  var imports = this.imports = {
73
- paths: env && env.paths || [], // Search paths, when importing
74
- queue: [], // Files which haven't been imported yet
75
- files: {}, // Holds the imported parse trees
76
- contents: {}, // Holds the imported file contents
77
- mime: env && env.mime, // MIME type of .less files
78
- error: null, // Error in parsing/evaluating an import
81
+ paths: env.paths || [], // Search paths, when importing
82
+ queue: [], // Files which haven't been imported yet
83
+ files: env.files, // Holds the imported parse trees
84
+ contents: env.contents, // Holds the imported file contents
85
+ mime: env.mime, // MIME type of .less files
86
+ error: null, // Error in parsing/evaluating an import
79
87
  push: function (path, callback) {
80
88
  var that = this;
81
89
  this.queue.push(path);
@@ -83,15 +91,18 @@ less.Parser = function Parser(env) {
83
91
  //
84
92
  // Import a file asynchronously
85
93
  //
86
- less.Parser.importer(path, this.paths, function (e, root, contents) {
94
+ less.Parser.importer(path, this.paths, function (e, root, fullPath) {
87
95
  that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
88
- that.files[path] = root; // Store the root
89
- that.contents[path] = contents;
96
+
97
+ var imported = fullPath in that.files;
98
+
99
+ that.files[fullPath] = root; // Store the root
90
100
 
91
101
  if (e && !that.error) { that.error = e }
92
- callback(e, root);
93
102
 
94
- if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
103
+ callback(e, root, imported);
104
+
105
+ if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing
95
106
  }, env);
96
107
  }
97
108
  };
@@ -105,11 +116,16 @@ less.Parser = function Parser(env) {
105
116
  current = i;
106
117
  }
107
118
  }
119
+ function isWhitespace(c) {
120
+ // Could change to \s?
121
+ var code = c.charCodeAt(0);
122
+ return code === 32 || code === 10 || code === 9;
123
+ }
108
124
  //
109
125
  // Parse from a token, regexp or string, and move forward if match
110
126
  //
111
127
  function $(tok) {
112
- var match, args, length, c, index, endIndex, k, mem;
128
+ var match, args, length, index, k;
113
129
 
114
130
  //
115
131
  // Non-terminal
@@ -142,18 +158,7 @@ less.Parser = function Parser(env) {
142
158
  // grammar is mostly white-space insensitive.
143
159
  //
144
160
  if (match) {
145
- mem = i += length;
146
- endIndex = i + chunks[j].length - length;
147
-
148
- while (i < endIndex) {
149
- c = input.charCodeAt(i);
150
- if (! (c === 32 || c === 10 || c === 9)) { break }
151
- i++;
152
- }
153
- chunks[j] = chunks[j].slice(length + (i - mem));
154
- current = i;
155
-
156
- if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
161
+ skipWhitespace(length);
157
162
 
158
163
  if(typeof(match) === 'string') {
159
164
  return match;
@@ -163,6 +168,23 @@ less.Parser = function Parser(env) {
163
168
  }
164
169
  }
165
170
 
171
+ function skipWhitespace(length) {
172
+ var oldi = i, oldj = j,
173
+ endIndex = i + chunks[j].length,
174
+ mem = i += length;
175
+
176
+ while (i < endIndex) {
177
+ if (! isWhitespace(input.charAt(i))) { break }
178
+ i++;
179
+ }
180
+ chunks[j] = chunks[j].slice(length + (i - mem));
181
+ current = i;
182
+
183
+ if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
184
+
185
+ return oldi !== i || oldj !== j;
186
+ }
187
+
166
188
  function expect(arg, msg) {
167
189
  var result = $(arg);
168
190
  if (! result) {
@@ -174,7 +196,10 @@ less.Parser = function Parser(env) {
174
196
  }
175
197
 
176
198
  function error(msg, type) {
177
- throw { index: i, type: type || 'Syntax', message: msg };
199
+ var e = new Error(msg);
200
+ e.index = i;
201
+ e.type = type || 'Syntax';
202
+ throw e;
178
203
  }
179
204
 
180
205
  // Same as $(), but don't change the state of the parser,
@@ -191,17 +216,9 @@ less.Parser = function Parser(env) {
191
216
  }
192
217
  }
193
218
 
194
- function basename(pathname) {
195
- if (less.mode === 'node') {
196
- return require('path').basename(pathname);
197
- } else {
198
- return pathname.match(/[^\/]+$/)[0];
199
- }
200
- }
201
-
202
219
  function getInput(e, env) {
203
220
  if (e.filename && env.filename && (e.filename !== env.filename)) {
204
- return parser.imports.contents[basename(e.filename)];
221
+ return parser.imports.contents[e.filename];
205
222
  } else {
206
223
  return input;
207
224
  }
@@ -216,6 +233,20 @@ less.Parser = function Parser(env) {
216
233
  column: column };
217
234
  }
218
235
 
236
+ function getFileName(e) {
237
+ if(less.mode === 'browser' || less.mode === 'rhino')
238
+ return e.filename;
239
+ else
240
+ return require('path').resolve(e.filename);
241
+ }
242
+
243
+ function getDebugInfo(index, inputStream, e) {
244
+ return {
245
+ lineNumber: getLocation(index, inputStream).line + 1,
246
+ fileName: getFileName(e)
247
+ };
248
+ }
249
+
219
250
  function LessError(e, env) {
220
251
  var input = getInput(e, env),
221
252
  loc = getLocation(e.index, input),
@@ -265,18 +296,21 @@ less.Parser = function Parser(env) {
265
296
  i = j = current = furthest = 0;
266
297
  input = str.replace(/\r\n/g, '\n');
267
298
 
299
+ // Remove potential UTF Byte Order Mark
300
+ input = input.replace(/^\uFEFF/, '');
301
+
268
302
  // Split the input into chunks.
269
303
  chunks = (function (chunks) {
270
304
  var j = 0,
271
- skip = /[^"'`\{\}\/\(\)\\]+/g,
305
+ skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
272
306
  comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
273
- string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
307
+ string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
274
308
  level = 0,
275
309
  match,
276
310
  chunk = chunks[0],
277
311
  inParam;
278
312
 
279
- for (var i = 0, c, cc; i < input.length; i++) {
313
+ for (var i = 0, c, cc; i < input.length;) {
280
314
  skip.lastIndex = i;
281
315
  if (match = skip.exec(input)) {
282
316
  if (match.index === i) {
@@ -291,7 +325,7 @@ less.Parser = function Parser(env) {
291
325
  if (match.index === i) {
292
326
  i += match[0].length;
293
327
  chunk.push(match[0]);
294
- c = input.charAt(i);
328
+ continue;
295
329
  }
296
330
  }
297
331
 
@@ -302,12 +336,12 @@ less.Parser = function Parser(env) {
302
336
  if (match.index === i) {
303
337
  i += match[0].length;
304
338
  chunk.push(match[0]);
305
- c = input.charAt(i);
339
+ continue;
306
340
  }
307
341
  }
308
342
  }
309
343
  }
310
-
344
+
311
345
  switch (c) {
312
346
  case '{': if (! inParam) { level ++; chunk.push(c); break }
313
347
  case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
@@ -315,12 +349,14 @@ less.Parser = function Parser(env) {
315
349
  case ')': if ( inParam) { inParam = false; chunk.push(c); break }
316
350
  default: chunk.push(c);
317
351
  }
352
+
353
+ i++;
318
354
  }
319
- if (level > 0) {
355
+ if (level != 0) {
320
356
  error = new(LessError)({
321
- index: i,
357
+ index: i-1,
322
358
  type: 'Parse',
323
- message: "missing closing `}`",
359
+ message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
324
360
  filename: env.filename
325
361
  }, env);
326
362
  }
@@ -329,7 +365,7 @@ less.Parser = function Parser(env) {
329
365
  })([[]]);
330
366
 
331
367
  if (error) {
332
- return callback(error);
368
+ return callback(error, env);
333
369
  }
334
370
 
335
371
  // Start with the primary rule.
@@ -380,7 +416,7 @@ less.Parser = function Parser(env) {
380
416
 
381
417
  try {
382
418
  var css = evaluate.call(this, { frames: frames })
383
- .toCSS([], { compress: options.compress || false });
419
+ .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers });
384
420
  } catch (e) {
385
421
  throw new(LessError)(e, env);
386
422
  }
@@ -391,7 +427,7 @@ less.Parser = function Parser(env) {
391
427
  }
392
428
 
393
429
  if (options.yuicompress && less.mode === 'node') {
394
- return require('./cssmin').compressor.cssmin(css);
430
+ return require('ycssmin').cssmin(css);
395
431
  } else if (options.compress) {
396
432
  return css.replace(/(\s)+/g, "$1");
397
433
  } else {
@@ -431,7 +467,11 @@ less.Parser = function Parser(env) {
431
467
  }
432
468
 
433
469
  if (this.imports.queue.length > 0) {
434
- finish = function () { callback(error, root) };
470
+ finish = function (e) {
471
+ e = error || e;
472
+ if (e) callback(e);
473
+ else callback(null, root);
474
+ };
435
475
  } else {
436
476
  callback(error, root);
437
477
  }
@@ -487,7 +527,7 @@ less.Parser = function Parser(env) {
487
527
 
488
528
  while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
489
529
  $(this.mixin.call) || $(this.comment) || $(this.directive))
490
- || $(/^[\s\n]+/)) {
530
+ || $(/^[\s\n]+/) || $(/^;+/)) {
491
531
  node && root.push(node);
492
532
  }
493
533
  return root;
@@ -538,7 +578,7 @@ less.Parser = function Parser(env) {
538
578
  keyword: function () {
539
579
  var k;
540
580
 
541
- if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
581
+ if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
542
582
  if (tree.colors.hasOwnProperty(k)) {
543
583
  // detect named color
544
584
  return new(tree.Color)(tree.colors[k].slice(1));
@@ -559,16 +599,22 @@ less.Parser = function Parser(env) {
559
599
  // The arguments are parsed with the `entities.arguments` parser.
560
600
  //
561
601
  call: function () {
562
- var name, args, index = i;
602
+ var name, nameLC, args, alpha_ret, index = i;
563
603
 
564
604
  if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
565
605
 
566
- name = name[1].toLowerCase();
606
+ name = name[1];
607
+ nameLC = name.toLowerCase();
567
608
 
568
- if (name === 'url') { return null }
609
+ if (nameLC === 'url') { return null }
569
610
  else { i += name.length }
570
611
 
571
- if (name === 'alpha') { return $(this.alpha) }
612
+ if (nameLC === 'alpha') {
613
+ alpha_ret = $(this.alpha);
614
+ if(typeof alpha_ret !== 'undefined') {
615
+ return alpha_ret;
616
+ }
617
+ }
572
618
 
573
619
  $('('); // Parse the '(' and consume whitespace.
574
620
 
@@ -588,9 +634,11 @@ less.Parser = function Parser(env) {
588
634
  return args;
589
635
  },
590
636
  literal: function () {
591
- return $(this.entities.dimension) ||
637
+ return $(this.entities.ratio) ||
638
+ $(this.entities.dimension) ||
592
639
  $(this.entities.color) ||
593
- $(this.entities.quoted);
640
+ $(this.entities.quoted) ||
641
+ $(this.entities.unicodeDescriptor);
594
642
  },
595
643
 
596
644
  // Assignments are argument entities for calls.
@@ -618,26 +666,12 @@ less.Parser = function Parser(env) {
618
666
 
619
667
  if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
620
668
  value = $(this.entities.quoted) || $(this.entities.variable) ||
621
- $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
669
+ $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
622
670
 
623
671
  expect(')');
624
672
 
625
- return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
626
- ? value : new(tree.Anonymous)(value), imports.paths);
627
- },
628
-
629
- dataURI: function () {
630
- var obj;
631
-
632
- if ($(/^data:/)) {
633
- obj = {};
634
- obj.mime = $(/^[^\/]+\/[^,;)]+/) || '';
635
- obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
636
- obj.base64 = $(/^;\s*base64/) || '';
637
- obj.data = $(/^,\s*[^)]+/);
638
-
639
- if (obj.data) { return obj }
640
- }
673
+ return new(tree.URL)((value.value != null || value instanceof tree.Variable)
674
+ ? value : new(tree.Anonymous)(value), env.rootpath);
641
675
  },
642
676
 
643
677
  //
@@ -656,6 +690,15 @@ less.Parser = function Parser(env) {
656
690
  }
657
691
  },
658
692
 
693
+ // A variable entity useing the protective {} e.g. @{var}
694
+ variableCurly: function () {
695
+ var name, curly, index = i;
696
+
697
+ if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
698
+ return new(tree.Variable)("@" + curly[1], index, env.filename);
699
+ }
700
+ },
701
+
659
702
  //
660
703
  // A Hexadecimal color
661
704
  //
@@ -666,7 +709,7 @@ less.Parser = function Parser(env) {
666
709
  color: function () {
667
710
  var rgb;
668
711
 
669
- if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
712
+ if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
670
713
  return new(tree.Color)(rgb[1]);
671
714
  }
672
715
  },
@@ -678,13 +721,41 @@ less.Parser = function Parser(env) {
678
721
  //
679
722
  dimension: function () {
680
723
  var value, c = input.charCodeAt(i);
681
- if ((c > 57 || c < 45) || c === 47) return;
724
+ //Is the first char of the dimension 0-9, '.', '+' or '-'
725
+ if ((c > 57 || c < 43) || c === 47 || c == 44) return;
682
726
 
683
- if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
727
+ if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) {
684
728
  return new(tree.Dimension)(value[1], value[2]);
685
729
  }
686
730
  },
687
731
 
732
+ //
733
+ // A Ratio
734
+ //
735
+ // 16/9
736
+ //
737
+ ratio: function () {
738
+ var value, c = input.charCodeAt(i);
739
+ if (c > 57 || c < 48) return;
740
+
741
+ if (value = $(/^(\d+\/\d+)/)) {
742
+ return new(tree.Ratio)(value[1]);
743
+ }
744
+ },
745
+
746
+ //
747
+ // A unicode descriptor, as is used in unicode-range
748
+ //
749
+ // U+0?? or U+00A1-00A9
750
+ //
751
+ unicodeDescriptor: function () {
752
+ var ud;
753
+
754
+ if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
755
+ return new(tree.UnicodeDescriptor)(ud[0]);
756
+ }
757
+ },
758
+
688
759
  //
689
760
  // JavaScript code to be evaluated
690
761
  //
@@ -727,9 +798,13 @@ less.Parser = function Parser(env) {
727
798
 
728
799
  if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
729
800
 
801
+ save();
802
+
730
803
  if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
731
804
  return new(tree.Shorthand)(a, b);
732
805
  }
806
+
807
+ restore();
733
808
  },
734
809
 
735
810
  //
@@ -748,23 +823,80 @@ less.Parser = function Parser(env) {
748
823
  // selector for now.
749
824
  //
750
825
  call: function () {
751
- var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
826
+ var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false;
752
827
 
753
828
  if (s !== '.' && s !== '#') { return }
829
+
830
+ save(); // stop us absorbing part of an invalid selector
754
831
 
755
- while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
832
+ while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
756
833
  elements.push(new(tree.Element)(c, e, i));
757
834
  c = $('>');
758
835
  }
759
- $('(') && (args = $(this.entities.arguments)) && $(')');
836
+ if ($('(')) {
837
+ expressions = [];
838
+ while (arg = $(this.expression)) {
839
+ nameLoop = null;
840
+ value = arg;
841
+
842
+ // Variable
843
+ if (arg.value.length == 1) {
844
+ var val = arg.value[0];
845
+ if (val instanceof tree.Variable) {
846
+ if ($(':')) {
847
+ if (expressions.length > 0) {
848
+ if (isSemiColonSeperated) {
849
+ error("Cannot mix ; and , as delimiter types");
850
+ }
851
+ expressionContainsNamed = true;
852
+ }
853
+ value = expect(this.expression);
854
+ nameLoop = (name = val.name);
855
+ }
856
+ }
857
+ }
858
+
859
+ expressions.push(value);
860
+
861
+ argsComma.push({ name: nameLoop, value: value });
862
+
863
+ if ($(',')) {
864
+ continue;
865
+ }
866
+
867
+ if ($(';') || isSemiColonSeperated) {
868
+
869
+ if (expressionContainsNamed) {
870
+ error("Cannot mix ; and , as delimiter types");
871
+ }
872
+
873
+ isSemiColonSeperated = true;
874
+
875
+ if (expressions.length > 1) {
876
+ value = new(tree.Value)(expressions);
877
+ }
878
+ argsSemiColon.push({ name: name, value: value });
879
+
880
+ name = null;
881
+ expressions = [];
882
+ expressionContainsNamed = false;
883
+ }
884
+ }
885
+
886
+ expect(')');
887
+ }
888
+
889
+ args = isSemiColonSeperated ? argsSemiColon : argsComma;
760
890
 
761
891
  if ($(this.important)) {
762
892
  important = true;
763
893
  }
764
894
 
765
895
  if (elements.length > 0 && ($(';') || peek('}'))) {
766
- return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
896
+ return new(tree.mixin.Call)(elements, args, index, env.filename, important);
767
897
  }
898
+
899
+ restore();
768
900
  },
769
901
 
770
902
  //
@@ -789,16 +921,18 @@ less.Parser = function Parser(env) {
789
921
  definition: function () {
790
922
  var name, params = [], match, ruleset, param, value, cond, variadic = false;
791
923
  if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
792
- peek(/^[^{]*(;|})/)) return;
924
+ peek(/^[^{]*\}/)) return;
793
925
 
794
926
  save();
795
927
 
796
- if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
928
+ if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
797
929
  name = match[1];
798
930
 
799
931
  do {
932
+ $(this.comment);
800
933
  if (input.charAt(i) === '.' && $(/^\.{3}/)) {
801
934
  variadic = true;
935
+ params.push({ variadic: true });
802
936
  break;
803
937
  } else if (param = $(this.entities.variable) || $(this.entities.literal)
804
938
  || $(this.entities.keyword)) {
@@ -820,9 +954,16 @@ less.Parser = function Parser(env) {
820
954
  } else {
821
955
  break;
822
956
  }
823
- } while ($(','))
957
+ } while ($(',') || $(';'))
824
958
 
825
- expect(')');
959
+ // .mixincall("@{a}");
960
+ // looks a bit like a mixin definition.. so we have to be nice and restore
961
+ if (!$(')')) {
962
+ furthest = i;
963
+ restore();
964
+ }
965
+
966
+ $(this.comment);
826
967
 
827
968
  if ($(/^when/)) { // Guard
828
969
  cond = expect(this.conditions, 'expected condition');
@@ -845,7 +986,7 @@ less.Parser = function Parser(env) {
845
986
  //
846
987
  entity: function () {
847
988
  return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
848
- $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) ||
989
+ $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) ||
849
990
  $(this.comment);
850
991
  },
851
992
 
@@ -889,18 +1030,22 @@ less.Parser = function Parser(env) {
889
1030
  var e, t, c, v;
890
1031
 
891
1032
  c = $(this.combinator);
892
- e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
893
- $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
1033
+
1034
+ e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
1035
+ $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly);
894
1036
 
895
1037
  if (! e) {
896
- $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
1038
+ if ($('(')) {
1039
+ if ((v = ($(this.entities.variableCurly) ||
1040
+ $(this.entities.variable) ||
1041
+ $(this.selector))) &&
1042
+ $(')')) {
1043
+ e = new(tree.Paren)(v);
1044
+ }
1045
+ }
897
1046
  }
898
1047
 
899
1048
  if (e) { return new(tree.Element)(c, e, i) }
900
-
901
- if (c.value && c.value.charAt(0) === '&') {
902
- return new(tree.Element)(c, null, i);
903
- }
904
1049
  },
905
1050
 
906
1051
  //
@@ -915,19 +1060,11 @@ less.Parser = function Parser(env) {
915
1060
  combinator: function () {
916
1061
  var match, c = input.charAt(i);
917
1062
 
918
- if (c === '>' || c === '+' || c === '~') {
1063
+ if (c === '>' || c === '+' || c === '~' || c === '|') {
919
1064
  i++;
920
- while (input.charAt(i) === ' ') { i++ }
1065
+ while (input.charAt(i).match(/\s/)) { i++ }
921
1066
  return new(tree.Combinator)(c);
922
- } else if (c === '&') {
923
- match = '&';
924
- i++;
925
- if(input.charAt(i) === ' ') {
926
- match = '& ';
927
- }
928
- while (input.charAt(i) === ' ') { i++ }
929
- return new(tree.Combinator)(match);
930
- } else if (input.charAt(i - 1) === ' ') {
1067
+ } else if (input.charAt(i - 1).match(/\s/)) {
931
1068
  return new(tree.Combinator)(" ");
932
1069
  } else {
933
1070
  return new(tree.Combinator)(null);
@@ -945,29 +1082,27 @@ less.Parser = function Parser(env) {
945
1082
  selector: function () {
946
1083
  var sel, e, elements = [], c, match;
947
1084
 
1085
+ // depreciated, will be removed soon
948
1086
  if ($('(')) {
949
1087
  sel = $(this.entity);
950
- expect(')');
1088
+ if (!$(')')) { return null; }
951
1089
  return new(tree.Selector)([new(tree.Element)('', sel, i)]);
952
1090
  }
953
1091
 
954
1092
  while (e = $(this.element)) {
955
1093
  c = input.charAt(i);
956
1094
  elements.push(e)
957
- if (c === '{' || c === '}' || c === ';' || c === ',') { break }
1095
+ if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
958
1096
  }
959
1097
 
960
1098
  if (elements.length > 0) { return new(tree.Selector)(elements) }
961
1099
  },
962
- tag: function () {
963
- return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
964
- },
965
1100
  attribute: function () {
966
1101
  var attr = '', key, val, op;
967
1102
 
968
1103
  if (! $('[')) return;
969
1104
 
970
- if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
1105
+ if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) {
971
1106
  if ((op = $(/^[|~*$^]?=/)) &&
972
1107
  (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
973
1108
  attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
@@ -985,7 +1120,6 @@ less.Parser = function Parser(env) {
985
1120
  //
986
1121
  block: function () {
987
1122
  var content;
988
-
989
1123
  if ($('{') && (content = $(this.primary)) && $('}')) {
990
1124
  return content;
991
1125
  }
@@ -995,9 +1129,13 @@ less.Parser = function Parser(env) {
995
1129
  // div, .class, body > p {...}
996
1130
  //
997
1131
  ruleset: function () {
998
- var selectors = [], s, rules, match;
1132
+ var selectors = [], s, rules, match, debugInfo;
1133
+
999
1134
  save();
1000
1135
 
1136
+ if (env.dumpLineNumbers)
1137
+ debugInfo = getDebugInfo(i, input, env);
1138
+
1001
1139
  while (s = $(this.selector)) {
1002
1140
  selectors.push(s);
1003
1141
  $(this.comment);
@@ -1006,7 +1144,10 @@ less.Parser = function Parser(env) {
1006
1144
  }
1007
1145
 
1008
1146
  if (selectors.length > 0 && (rules = $(this.block))) {
1009
- return new(tree.Ruleset)(selectors, rules, env.strictImports);
1147
+ var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
1148
+ if (env.dumpLineNumbers)
1149
+ ruleset.debugInfo = debugInfo;
1150
+ return ruleset;
1010
1151
  } else {
1011
1152
  // Backtrack
1012
1153
  furthest = i;
@@ -1051,13 +1192,19 @@ less.Parser = function Parser(env) {
1051
1192
  //
1052
1193
  "import": function () {
1053
1194
  var path, features, index = i;
1054
- if ($(/^@import\s+/) &&
1055
- (path = $(this.entities.quoted) || $(this.entities.url))) {
1195
+
1196
+ save();
1197
+
1198
+ var dir = $(/^@import(?:-(once))?\s+/);
1199
+
1200
+ if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
1056
1201
  features = $(this.mediaFeatures);
1057
1202
  if ($(';')) {
1058
- return new(tree.Import)(path, imports, features, index);
1203
+ return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath);
1059
1204
  }
1060
1205
  }
1206
+
1207
+ restore();
1061
1208
  },
1062
1209
 
1063
1210
  mediaFeature: function () {
@@ -1088,7 +1235,7 @@ less.Parser = function Parser(env) {
1088
1235
 
1089
1236
  mediaFeatures: function () {
1090
1237
  var e, features = [];
1091
-
1238
+
1092
1239
  do {
1093
1240
  if (e = $(this.mediaFeature)) {
1094
1241
  features.push(e);
@@ -1098,18 +1245,24 @@ less.Parser = function Parser(env) {
1098
1245
  if (! $(',')) { break }
1099
1246
  }
1100
1247
  } while (e);
1101
-
1248
+
1102
1249
  return features.length > 0 ? features : null;
1103
1250
  },
1104
1251
 
1105
1252
  media: function () {
1106
- var features, rules;
1253
+ var features, rules, media, debugInfo;
1254
+
1255
+ if (env.dumpLineNumbers)
1256
+ debugInfo = getDebugInfo(i, input, env);
1107
1257
 
1108
1258
  if ($(/^@media/)) {
1109
1259
  features = $(this.mediaFeatures);
1110
1260
 
1111
1261
  if (rules = $(this.block)) {
1112
- return new(tree.Media)(rules, features);
1262
+ media = new(tree.Media)(rules, features);
1263
+ if(env.dumpLineNumbers)
1264
+ media.debugInfo = debugInfo;
1265
+ return media;
1113
1266
  }
1114
1267
  }
1115
1268
  },
@@ -1120,26 +1273,81 @@ less.Parser = function Parser(env) {
1120
1273
  // @charset "utf-8";
1121
1274
  //
1122
1275
  directive: function () {
1123
- var name, value, rules, types, e, nodes;
1276
+ var name, value, rules, identifier, e, nodes, nonVendorSpecificName,
1277
+ hasBlock, hasIdentifier, hasExpression;
1124
1278
 
1125
1279
  if (input.charAt(i) !== '@') return;
1126
1280
 
1127
1281
  if (value = $(this['import']) || $(this.media)) {
1128
1282
  return value;
1129
- } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
1130
- types = ($(/^[^{]+/) || '').trim();
1283
+ }
1284
+
1285
+ save();
1286
+
1287
+ name = $(/^@[a-z-]+/);
1288
+
1289
+ if (!name) return;
1290
+
1291
+ nonVendorSpecificName = name;
1292
+ if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
1293
+ nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
1294
+ }
1295
+
1296
+ switch(nonVendorSpecificName) {
1297
+ case "@font-face":
1298
+ hasBlock = true;
1299
+ break;
1300
+ case "@viewport":
1301
+ case "@top-left":
1302
+ case "@top-left-corner":
1303
+ case "@top-center":
1304
+ case "@top-right":
1305
+ case "@top-right-corner":
1306
+ case "@bottom-left":
1307
+ case "@bottom-left-corner":
1308
+ case "@bottom-center":
1309
+ case "@bottom-right":
1310
+ case "@bottom-right-corner":
1311
+ case "@left-top":
1312
+ case "@left-middle":
1313
+ case "@left-bottom":
1314
+ case "@right-top":
1315
+ case "@right-middle":
1316
+ case "@right-bottom":
1317
+ hasBlock = true;
1318
+ break;
1319
+ case "@page":
1320
+ case "@document":
1321
+ case "@supports":
1322
+ case "@keyframes":
1323
+ hasBlock = true;
1324
+ hasIdentifier = true;
1325
+ break;
1326
+ case "@namespace":
1327
+ hasExpression = true;
1328
+ break;
1329
+ }
1330
+
1331
+ if (hasIdentifier) {
1332
+ name += " " + ($(/^[^{]+/) || '').trim();
1333
+ }
1334
+
1335
+ if (hasBlock)
1336
+ {
1131
1337
  if (rules = $(this.block)) {
1132
- return new(tree.Directive)(name + " " + types, rules);
1338
+ return new(tree.Directive)(name, rules);
1133
1339
  }
1134
- } else if (name = $(/^@[-a-z]+/)) {
1135
- if (name === '@font-face') {
1136
- if (rules = $(this.block)) {
1137
- return new(tree.Directive)(name, rules);
1340
+ } else {
1341
+ if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
1342
+ var directive = new(tree.Directive)(name, value);
1343
+ if (env.dumpLineNumbers) {
1344
+ directive.debugInfo = getDebugInfo(i, input, env);
1138
1345
  }
1139
- } else if ((value = $(this.entity)) && $(';')) {
1140
- return new(tree.Directive)(name, value);
1346
+ return directive;
1141
1347
  }
1142
1348
  }
1349
+
1350
+ restore();
1143
1351
  },
1144
1352
  font: function () {
1145
1353
  var value = [], expression = [], weight, shorthand, font, e;
@@ -1193,7 +1401,7 @@ less.Parser = function Parser(env) {
1193
1401
  multiplication: function () {
1194
1402
  var m, a, op, operation;
1195
1403
  if (m = $(this.operand)) {
1196
- while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
1404
+ while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
1197
1405
  operation = new(tree.Operation)(op, [operation || m, a]);
1198
1406
  }
1199
1407
  return operation || m;
@@ -1202,7 +1410,7 @@ less.Parser = function Parser(env) {
1202
1410
  addition: function () {
1203
1411
  var m, a, op, operation;
1204
1412
  if (m = $(this.multiplication)) {
1205
- while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
1413
+ while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) &&
1206
1414
  (a = $(this.multiplication))) {
1207
1415
  operation = new(tree.Operation)(op, [operation || m, a]);
1208
1416
  }
@@ -1274,7 +1482,7 @@ less.Parser = function Parser(env) {
1274
1482
  property: function () {
1275
1483
  var name;
1276
1484
 
1277
- if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
1485
+ if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) {
1278
1486
  return name[1];
1279
1487
  }
1280
1488
  }
@@ -1287,17 +1495,26 @@ if (less.mode === 'browser' || less.mode === 'rhino') {
1287
1495
  // Used by `@import` directives
1288
1496
  //
1289
1497
  less.Parser.importer = function (path, paths, callback, env) {
1290
- if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
1498
+ if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) {
1291
1499
  path = paths[0] + path;
1292
1500
  }
1293
1501
  // We pass `true` as 3rd argument, to force the reload of the import.
1294
1502
  // This is so we can get the syntax tree as opposed to just the CSS output,
1295
1503
  // as we need this to evaluate the current stylesheet.
1296
- loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
1504
+ loadStyleSheet({
1505
+ href: path,
1506
+ title: path,
1507
+ type: env.mime,
1508
+ contents: env.contents,
1509
+ files: env.files,
1510
+ rootpath: env.rootpath,
1511
+ entryPath: env.entryPath,
1512
+ relativeUrls: env.relativeUrls },
1513
+ function (e, root, data, sheet, _, path) {
1297
1514
  if (e && typeof(env.errback) === "function") {
1298
1515
  env.errback.call(null, path, paths, callback, env);
1299
1516
  } else {
1300
- callback.apply(null, arguments);
1517
+ callback.call(null, e, root, path);
1301
1518
  }
1302
1519
  }, true);
1303
1520
  };