less 2.3.0 → 2.3.1

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 (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
  };