less 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitmodules +0 -3
- data/.travis.yml +10 -0
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/bin/lessc +21 -2
- data/less.gemspec +5 -3
- data/lib/less/defaults.rb +13 -0
- data/lib/less/js/CHANGELOG +41 -0
- data/lib/less/js/Makefile +21 -2
- data/lib/less/js/benchmark/benchmark.less +11 -11
- data/lib/less/js/benchmark/less-benchmark.js +3 -5
- data/lib/less/js/bin/lessc +52 -18
- data/lib/less/js/build/amd.js +6 -0
- data/lib/less/js/build/require-rhino.js +7 -0
- data/lib/less/js/dist/{less-1.0.44.js → less-1.1.4.js} +159 -45
- data/lib/less/js/dist/less-1.1.4.min.js +16 -0
- data/lib/less/js/dist/less-1.1.5.js +2805 -0
- data/lib/less/js/dist/less-1.1.5.min.js +9 -0
- data/lib/less/js/dist/less-1.1.6.js +3004 -0
- data/lib/less/js/dist/less-1.1.6.min.js +9 -0
- data/lib/less/js/dist/less-1.2.0.js +3293 -0
- data/lib/less/js/dist/less-1.2.0.min.js +9 -0
- data/lib/less/js/dist/less-1.2.1.js +3318 -0
- data/lib/less/js/dist/less-1.2.1.min.js +9 -0
- data/lib/less/js/dist/less-1.2.2.js +3337 -0
- data/lib/less/js/dist/less-1.2.2.min.js +9 -0
- data/lib/less/js/dist/less-1.3.0.js +3478 -0
- data/lib/less/js/dist/less-1.3.0.min.js +9 -0
- data/lib/less/js/dist/less-rhino-1.1.3.js +2460 -0
- data/lib/less/js/dist/less-rhino-1.1.5.js +2481 -0
- data/lib/less/js/lib/less/browser.js +38 -27
- data/lib/less/js/lib/less/colors.js +151 -0
- data/lib/less/js/lib/less/cssmin.js +355 -0
- data/lib/less/js/lib/less/functions.js +61 -7
- data/lib/less/js/lib/less/index.js +48 -37
- data/lib/less/js/lib/less/parser.js +327 -120
- data/lib/less/js/lib/less/rhino.js +62 -0
- data/lib/less/js/lib/less/tree/alpha.js +1 -1
- data/lib/less/js/lib/less/tree/anonymous.js +1 -1
- data/lib/less/js/lib/less/tree/assignment.js +17 -0
- data/lib/less/js/lib/less/tree/call.js +7 -4
- data/lib/less/js/lib/less/tree/color.js +9 -6
- data/lib/less/js/lib/less/tree/comment.js +1 -1
- data/lib/less/js/lib/less/tree/condition.js +42 -0
- data/lib/less/js/lib/less/tree/dimension.js +16 -1
- data/lib/less/js/lib/less/tree/directive.js +4 -2
- data/lib/less/js/lib/less/tree/element.js +20 -5
- data/lib/less/js/lib/less/tree/expression.js +2 -2
- data/lib/less/js/lib/less/tree/import.js +16 -14
- data/lib/less/js/lib/less/tree/javascript.js +1 -1
- data/lib/less/js/lib/less/tree/keyword.js +12 -2
- data/lib/less/js/lib/less/tree/media.js +114 -0
- data/lib/less/js/lib/less/tree/mixin.js +49 -20
- data/lib/less/js/lib/less/tree/operation.js +1 -1
- data/lib/less/js/lib/less/tree/paren.js +16 -0
- data/lib/less/js/lib/less/tree/quoted.js +2 -2
- data/lib/less/js/lib/less/tree/rule.js +8 -4
- data/lib/less/js/lib/less/tree/ruleset.js +49 -12
- data/lib/less/js/lib/less/tree/selector.js +18 -4
- data/lib/less/js/lib/less/tree/url.js +2 -2
- data/lib/less/js/lib/less/tree/value.js +1 -1
- data/lib/less/js/lib/less/tree/variable.js +5 -3
- data/lib/less/js/lib/less/tree.js +6 -2
- data/lib/less/js/package.json +2 -2
- data/lib/less/js/test/css/colors.css +16 -0
- data/lib/less/js/test/css/comments.css +9 -5
- data/lib/less/js/test/css/css-3.css +18 -2
- data/lib/less/js/test/css/css-escapes.css +1 -1
- data/lib/less/js/test/css/css.css +11 -4
- data/lib/less/js/test/css/functions.css +13 -0
- data/lib/less/js/test/css/ie-filters.css +5 -0
- data/lib/less/js/test/css/import.css +12 -3
- data/lib/less/js/test/css/media.css +60 -2
- data/lib/less/js/test/css/mixins-args.css +17 -2
- data/lib/less/js/test/css/mixins-guards.css +58 -0
- data/lib/less/js/test/css/mixins-important.css +17 -0
- data/lib/less/js/test/css/mixins-pattern.css +4 -6
- data/lib/less/js/test/css/mixins.css +21 -0
- data/lib/less/js/test/css/operations.css +3 -0
- data/lib/less/js/test/css/parens.css +1 -1
- data/lib/less/js/test/css/rulesets.css +6 -2
- data/lib/less/js/test/css/scope.css +6 -6
- data/lib/less/js/test/css/selectors.css +38 -1
- data/lib/less/js/test/css/strings.css +6 -4
- data/lib/less/js/test/css/variables.css +3 -0
- data/lib/less/js/test/css/whitespace.css +5 -3
- data/lib/less/js/test/less/colors.less +19 -0
- data/lib/less/js/test/less/comments.less +8 -6
- data/lib/less/js/test/less/css-3.less +10 -0
- data/lib/less/js/test/less/css.less +4 -0
- data/lib/less/js/test/less/functions.less +15 -1
- data/lib/less/js/test/less/ie-filters.less +8 -0
- data/lib/less/js/test/less/import/import-test-e.less +2 -0
- data/lib/less/js/test/less/import.less +4 -1
- data/lib/less/js/test/less/media.less +55 -1
- data/lib/less/js/test/less/mixins-args.less +20 -1
- data/lib/less/js/test/less/mixins-guards.less +94 -0
- data/lib/less/js/test/less/mixins-important.less +18 -0
- data/lib/less/js/test/less/mixins-pattern.less +3 -0
- data/lib/less/js/test/less/mixins.less +20 -0
- data/lib/less/js/test/less/operations.less +4 -0
- data/lib/less/js/test/less/selectors.less +31 -0
- data/lib/less/js/test/less/strings.less +2 -0
- data/lib/less/js/test/less/variables.less +4 -0
- data/lib/less/js/test/less-test.js +3 -5
- data/lib/less/loader.rb +24 -25
- data/lib/less/parser.rb +32 -6
- data/lib/less/version.rb +1 -1
- data/lib/less.rb +7 -8
- data/spec/less/faulty/faulty.less +3 -0
- data/spec/less/parser_spec.rb +28 -2
- metadata +321 -149
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
var less, tree;
|
|
2
2
|
|
|
3
|
-
if (typeof(
|
|
3
|
+
if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
|
|
4
|
+
// Rhino
|
|
5
|
+
// Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
|
|
6
|
+
if (typeof(window) === 'undefined') { less = {} }
|
|
7
|
+
else { less = window.less = {} }
|
|
8
|
+
tree = less.tree = {};
|
|
9
|
+
less.mode = 'rhino';
|
|
10
|
+
} else if (typeof(window) === 'undefined') {
|
|
11
|
+
// Node.js
|
|
4
12
|
less = exports,
|
|
5
|
-
tree = require('
|
|
13
|
+
tree = require('./tree');
|
|
14
|
+
less.mode = 'node';
|
|
6
15
|
} else {
|
|
16
|
+
// Browser
|
|
7
17
|
if (typeof(window.less) === 'undefined') { window.less = {} }
|
|
8
18
|
less = window.less,
|
|
9
19
|
tree = window.less.tree = {};
|
|
20
|
+
less.mode = 'browser';
|
|
10
21
|
}
|
|
11
22
|
//
|
|
12
23
|
// less.js - parser
|
|
@@ -62,7 +73,9 @@ less.Parser = function Parser(env) {
|
|
|
62
73
|
paths: env && env.paths || [], // Search paths, when importing
|
|
63
74
|
queue: [], // Files which haven't been imported yet
|
|
64
75
|
files: {}, // Holds the imported parse trees
|
|
76
|
+
contents: {}, // Holds the imported file contents
|
|
65
77
|
mime: env && env.mime, // MIME type of .less files
|
|
78
|
+
error: null, // Error in parsing/evaluating an import
|
|
66
79
|
push: function (path, callback) {
|
|
67
80
|
var that = this;
|
|
68
81
|
this.queue.push(path);
|
|
@@ -70,11 +83,13 @@ less.Parser = function Parser(env) {
|
|
|
70
83
|
//
|
|
71
84
|
// Import a file asynchronously
|
|
72
85
|
//
|
|
73
|
-
less.Parser.importer(path, this.paths, function (root) {
|
|
86
|
+
less.Parser.importer(path, this.paths, function (e, root, contents) {
|
|
74
87
|
that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
|
|
75
88
|
that.files[path] = root; // Store the root
|
|
89
|
+
that.contents[path] = contents;
|
|
76
90
|
|
|
77
|
-
|
|
91
|
+
if (e && !that.error) { that.error = e }
|
|
92
|
+
callback(e, root);
|
|
78
93
|
|
|
79
94
|
if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
|
|
80
95
|
}, env);
|
|
@@ -148,6 +163,20 @@ less.Parser = function Parser(env) {
|
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
165
|
|
|
166
|
+
function expect(arg, msg) {
|
|
167
|
+
var result = $(arg);
|
|
168
|
+
if (! result) {
|
|
169
|
+
error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
|
|
170
|
+
: "unexpected token"));
|
|
171
|
+
} else {
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function error(msg, type) {
|
|
177
|
+
throw { index: i, type: type || 'Syntax', message: msg };
|
|
178
|
+
}
|
|
179
|
+
|
|
151
180
|
// Same as $(), but don't change the state of the parser,
|
|
152
181
|
// just return the match.
|
|
153
182
|
function peek(tok) {
|
|
@@ -162,6 +191,54 @@ less.Parser = function Parser(env) {
|
|
|
162
191
|
}
|
|
163
192
|
}
|
|
164
193
|
|
|
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
|
+
function getInput(e, env) {
|
|
203
|
+
if (e.filename && env.filename && (e.filename !== env.filename)) {
|
|
204
|
+
return parser.imports.contents[basename(e.filename)];
|
|
205
|
+
} else {
|
|
206
|
+
return input;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getLocation(index, input) {
|
|
211
|
+
for (var n = index, column = -1;
|
|
212
|
+
n >= 0 && input.charAt(n) !== '\n';
|
|
213
|
+
n--) { column++ }
|
|
214
|
+
|
|
215
|
+
return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
|
|
216
|
+
column: column };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function LessError(e, env) {
|
|
220
|
+
var input = getInput(e, env),
|
|
221
|
+
loc = getLocation(e.index, input),
|
|
222
|
+
line = loc.line,
|
|
223
|
+
col = loc.column,
|
|
224
|
+
lines = input.split('\n');
|
|
225
|
+
|
|
226
|
+
this.type = e.type || 'Syntax';
|
|
227
|
+
this.message = e.message;
|
|
228
|
+
this.filename = e.filename || env.filename;
|
|
229
|
+
this.index = e.index;
|
|
230
|
+
this.line = typeof(line) === 'number' ? line + 1 : null;
|
|
231
|
+
this.callLine = e.call && (getLocation(e.call, input).line + 1);
|
|
232
|
+
this.callExtract = lines[getLocation(e.call, input).line];
|
|
233
|
+
this.stack = e.stack;
|
|
234
|
+
this.column = col;
|
|
235
|
+
this.extract = [
|
|
236
|
+
lines[line - 1],
|
|
237
|
+
lines[line],
|
|
238
|
+
lines[line + 1]
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
|
|
165
242
|
this.env = env = env || {};
|
|
166
243
|
|
|
167
244
|
// The optimization level dictates the thoroughness of the parser,
|
|
@@ -186,19 +263,18 @@ less.Parser = function Parser(env) {
|
|
|
186
263
|
var root, start, end, zone, line, lines, buff = [], c, error = null;
|
|
187
264
|
|
|
188
265
|
i = j = current = furthest = 0;
|
|
189
|
-
chunks = [];
|
|
190
266
|
input = str.replace(/\r\n/g, '\n');
|
|
191
267
|
|
|
192
268
|
// Split the input into chunks.
|
|
193
269
|
chunks = (function (chunks) {
|
|
194
270
|
var j = 0,
|
|
195
|
-
skip = /[^"'`\{\}\/\(\)]+/g,
|
|
271
|
+
skip = /[^"'`\{\}\/\(\)\\]+/g,
|
|
196
272
|
comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
|
|
273
|
+
string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
|
|
197
274
|
level = 0,
|
|
198
275
|
match,
|
|
199
276
|
chunk = chunks[0],
|
|
200
|
-
inParam
|
|
201
|
-
inString;
|
|
277
|
+
inParam;
|
|
202
278
|
|
|
203
279
|
for (var i = 0, c, cc; i < input.length; i++) {
|
|
204
280
|
skip.lastIndex = i;
|
|
@@ -209,9 +285,17 @@ less.Parser = function Parser(env) {
|
|
|
209
285
|
}
|
|
210
286
|
}
|
|
211
287
|
c = input.charAt(i);
|
|
212
|
-
comment.lastIndex = i;
|
|
288
|
+
comment.lastIndex = string.lastIndex = i;
|
|
213
289
|
|
|
214
|
-
if (
|
|
290
|
+
if (match = string.exec(input)) {
|
|
291
|
+
if (match.index === i) {
|
|
292
|
+
i += match[0].length;
|
|
293
|
+
chunk.push(match[0]);
|
|
294
|
+
c = input.charAt(i);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (!inParam && c === '/') {
|
|
215
299
|
cc = input.charAt(i + 1);
|
|
216
300
|
if (cc === '/' || cc === '*') {
|
|
217
301
|
if (match = comment.exec(input)) {
|
|
@@ -224,51 +308,46 @@ less.Parser = function Parser(env) {
|
|
|
224
308
|
}
|
|
225
309
|
}
|
|
226
310
|
|
|
227
|
-
|
|
228
|
-
chunk.push(c);
|
|
229
|
-
|
|
230
|
-
chunk.push(c);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
chunk.push(c);
|
|
234
|
-
inParam = true;
|
|
235
|
-
} else if (c === ')' && !inString && inParam) {
|
|
236
|
-
chunk.push(c);
|
|
237
|
-
inParam = false;
|
|
238
|
-
} else {
|
|
239
|
-
if (c === '"' || c === "'" || c === '`') {
|
|
240
|
-
if (! inString) {
|
|
241
|
-
inString = c;
|
|
242
|
-
} else {
|
|
243
|
-
inString = inString === c ? false : inString;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
chunk.push(c);
|
|
311
|
+
switch (c) {
|
|
312
|
+
case '{': if (! inParam) { level ++; chunk.push(c); break }
|
|
313
|
+
case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
|
|
314
|
+
case '(': if (! inParam) { inParam = true; chunk.push(c); break }
|
|
315
|
+
case ')': if ( inParam) { inParam = false; chunk.push(c); break }
|
|
316
|
+
default: chunk.push(c);
|
|
247
317
|
}
|
|
248
318
|
}
|
|
249
319
|
if (level > 0) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
320
|
+
error = new(LessError)({
|
|
321
|
+
index: i,
|
|
322
|
+
type: 'Parse',
|
|
323
|
+
message: "missing closing `}`",
|
|
253
324
|
filename: env.filename
|
|
254
|
-
};
|
|
325
|
+
}, env);
|
|
255
326
|
}
|
|
256
327
|
|
|
257
328
|
return chunks.map(function (c) { return c.join('') });;
|
|
258
329
|
})([[]]);
|
|
259
330
|
|
|
331
|
+
if (error) {
|
|
332
|
+
return callback(error);
|
|
333
|
+
}
|
|
334
|
+
|
|
260
335
|
// Start with the primary rule.
|
|
261
336
|
// The whole syntax tree is held under a Ruleset node,
|
|
262
337
|
// with the `root` property set to true, so no `{}` are
|
|
263
338
|
// output. The callback is called when the input is parsed.
|
|
264
|
-
|
|
265
|
-
|
|
339
|
+
try {
|
|
340
|
+
root = new(tree.Ruleset)([], $(this.parsers.primary));
|
|
341
|
+
root.root = true;
|
|
342
|
+
} catch (e) {
|
|
343
|
+
return callback(new(LessError)(e, env));
|
|
344
|
+
}
|
|
266
345
|
|
|
267
346
|
root.toCSS = (function (evaluate) {
|
|
268
347
|
var line, lines, column;
|
|
269
348
|
|
|
270
349
|
return function (options, variables) {
|
|
271
|
-
var frames = [];
|
|
350
|
+
var frames = [], importError;
|
|
272
351
|
|
|
273
352
|
options = options || {};
|
|
274
353
|
//
|
|
@@ -303,39 +382,21 @@ less.Parser = function Parser(env) {
|
|
|
303
382
|
var css = evaluate.call(this, { frames: frames })
|
|
304
383
|
.toCSS([], { compress: options.compress || false });
|
|
305
384
|
} catch (e) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
throw {
|
|
314
|
-
type: e.type,
|
|
315
|
-
message: e.message,
|
|
316
|
-
filename: env.filename,
|
|
317
|
-
index: e.index,
|
|
318
|
-
line: typeof(line) === 'number' ? line + 1 : null,
|
|
319
|
-
callLine: e.call && (getLine(e.call) + 1),
|
|
320
|
-
callExtract: lines[getLine(e.call)],
|
|
321
|
-
stack: e.stack,
|
|
322
|
-
column: column,
|
|
323
|
-
extract: [
|
|
324
|
-
lines[line - 1],
|
|
325
|
-
lines[line],
|
|
326
|
-
lines[line + 1]
|
|
327
|
-
]
|
|
328
|
-
};
|
|
385
|
+
throw new(LessError)(e, env);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if ((importError = parser.imports.error)) { // Check if there was an error during importing
|
|
389
|
+
if (importError instanceof LessError) throw importError;
|
|
390
|
+
else throw new(LessError)(importError, env);
|
|
329
391
|
}
|
|
330
|
-
|
|
392
|
+
|
|
393
|
+
if (options.yuicompress && less.mode === 'node') {
|
|
394
|
+
return require('./cssmin').compressor.cssmin(css);
|
|
395
|
+
} else if (options.compress) {
|
|
331
396
|
return css.replace(/(\s)+/g, "$1");
|
|
332
397
|
} else {
|
|
333
398
|
return css;
|
|
334
399
|
}
|
|
335
|
-
|
|
336
|
-
function getLine(index) {
|
|
337
|
-
return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
|
|
338
|
-
}
|
|
339
400
|
};
|
|
340
401
|
})(root.eval);
|
|
341
402
|
|
|
@@ -355,7 +416,7 @@ less.Parser = function Parser(env) {
|
|
|
355
416
|
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
|
|
356
417
|
|
|
357
418
|
error = {
|
|
358
|
-
|
|
419
|
+
type: "Parse",
|
|
359
420
|
message: "Syntax Error on line " + line,
|
|
360
421
|
index: i,
|
|
361
422
|
filename: env.filename,
|
|
@@ -476,7 +537,15 @@ less.Parser = function Parser(env) {
|
|
|
476
537
|
//
|
|
477
538
|
keyword: function () {
|
|
478
539
|
var k;
|
|
479
|
-
|
|
540
|
+
|
|
541
|
+
if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
|
|
542
|
+
if (tree.colors.hasOwnProperty(k)) {
|
|
543
|
+
// detect named color
|
|
544
|
+
return new(tree.Color)(tree.colors[k].slice(1));
|
|
545
|
+
} else {
|
|
546
|
+
return new(tree.Keyword)(k);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
480
549
|
},
|
|
481
550
|
|
|
482
551
|
//
|
|
@@ -492,7 +561,7 @@ less.Parser = function Parser(env) {
|
|
|
492
561
|
call: function () {
|
|
493
562
|
var name, args, index = i;
|
|
494
563
|
|
|
495
|
-
if (! (name = /^([\w-]
|
|
564
|
+
if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
|
|
496
565
|
|
|
497
566
|
name = name[1].toLowerCase();
|
|
498
567
|
|
|
@@ -507,12 +576,12 @@ less.Parser = function Parser(env) {
|
|
|
507
576
|
|
|
508
577
|
if (! $(')')) return;
|
|
509
578
|
|
|
510
|
-
if (name) { return new(tree.Call)(name, args, index) }
|
|
579
|
+
if (name) { return new(tree.Call)(name, args, index, env.filename) }
|
|
511
580
|
},
|
|
512
581
|
arguments: function () {
|
|
513
582
|
var args = [], arg;
|
|
514
583
|
|
|
515
|
-
while (arg = $(this.expression)) {
|
|
584
|
+
while (arg = $(this.entities.assignment) || $(this.expression)) {
|
|
516
585
|
args.push(arg);
|
|
517
586
|
if (! $(',')) { break }
|
|
518
587
|
}
|
|
@@ -524,6 +593,19 @@ less.Parser = function Parser(env) {
|
|
|
524
593
|
$(this.entities.quoted);
|
|
525
594
|
},
|
|
526
595
|
|
|
596
|
+
// Assignments are argument entities for calls.
|
|
597
|
+
// They are present in ie filter properties as shown below.
|
|
598
|
+
//
|
|
599
|
+
// filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
|
|
600
|
+
//
|
|
601
|
+
|
|
602
|
+
assignment: function () {
|
|
603
|
+
var key, value;
|
|
604
|
+
if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
|
|
605
|
+
return new(tree.Assignment)(key, value);
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
|
|
527
609
|
//
|
|
528
610
|
// Parse url() tokens
|
|
529
611
|
//
|
|
@@ -537,7 +619,8 @@ less.Parser = function Parser(env) {
|
|
|
537
619
|
if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
|
|
538
620
|
value = $(this.entities.quoted) || $(this.entities.variable) ||
|
|
539
621
|
$(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
|
|
540
|
-
|
|
622
|
+
|
|
623
|
+
expect(')');
|
|
541
624
|
|
|
542
625
|
return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
|
|
543
626
|
? value : new(tree.Anonymous)(value), imports.paths);
|
|
@@ -569,7 +652,7 @@ less.Parser = function Parser(env) {
|
|
|
569
652
|
var name, index = i;
|
|
570
653
|
|
|
571
654
|
if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
|
|
572
|
-
return new(tree.Variable)(name, index);
|
|
655
|
+
return new(tree.Variable)(name, index, env.filename);
|
|
573
656
|
}
|
|
574
657
|
},
|
|
575
658
|
|
|
@@ -597,7 +680,7 @@ less.Parser = function Parser(env) {
|
|
|
597
680
|
var value, c = input.charCodeAt(i);
|
|
598
681
|
if ((c > 57 || c < 45) || c === 47) return;
|
|
599
682
|
|
|
600
|
-
if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
|
|
683
|
+
if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
|
|
601
684
|
return new(tree.Dimension)(value[1], value[2]);
|
|
602
685
|
}
|
|
603
686
|
},
|
|
@@ -665,18 +748,22 @@ less.Parser = function Parser(env) {
|
|
|
665
748
|
// selector for now.
|
|
666
749
|
//
|
|
667
750
|
call: function () {
|
|
668
|
-
var elements = [], e, c, args, index = i, s = input.charAt(i);
|
|
751
|
+
var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
|
|
669
752
|
|
|
670
753
|
if (s !== '.' && s !== '#') { return }
|
|
671
754
|
|
|
672
755
|
while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
|
|
673
|
-
elements.push(new(tree.Element)(c, e));
|
|
756
|
+
elements.push(new(tree.Element)(c, e, i));
|
|
674
757
|
c = $('>');
|
|
675
758
|
}
|
|
676
759
|
$('(') && (args = $(this.entities.arguments)) && $(')');
|
|
677
760
|
|
|
761
|
+
if ($(this.important)) {
|
|
762
|
+
important = true;
|
|
763
|
+
}
|
|
764
|
+
|
|
678
765
|
if (elements.length > 0 && ($(';') || peek('}'))) {
|
|
679
|
-
return new(tree.mixin.Call)(elements, args, index);
|
|
766
|
+
return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
|
|
680
767
|
}
|
|
681
768
|
},
|
|
682
769
|
|
|
@@ -700,38 +787,53 @@ less.Parser = function Parser(env) {
|
|
|
700
787
|
// the `{...}` block.
|
|
701
788
|
//
|
|
702
789
|
definition: function () {
|
|
703
|
-
var name, params = [], match, ruleset, param, value;
|
|
704
|
-
|
|
790
|
+
var name, params = [], match, ruleset, param, value, cond, variadic = false;
|
|
705
791
|
if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
|
|
706
792
|
peek(/^[^{]*(;|})/)) return;
|
|
707
793
|
|
|
794
|
+
save();
|
|
795
|
+
|
|
708
796
|
if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
|
|
709
797
|
name = match[1];
|
|
710
798
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
799
|
+
do {
|
|
800
|
+
if (input.charAt(i) === '.' && $(/^\.{3}/)) {
|
|
801
|
+
variadic = true;
|
|
802
|
+
break;
|
|
803
|
+
} else if (param = $(this.entities.variable) || $(this.entities.literal)
|
|
804
|
+
|| $(this.entities.keyword)) {
|
|
805
|
+
// Variable
|
|
806
|
+
if (param instanceof tree.Variable) {
|
|
807
|
+
if ($(':')) {
|
|
808
|
+
value = expect(this.expression, 'expected expression');
|
|
717
809
|
params.push({ name: param.name, value: value });
|
|
810
|
+
} else if ($(/^\.{3}/)) {
|
|
811
|
+
params.push({ name: param.name, variadic: true });
|
|
812
|
+
variadic = true;
|
|
813
|
+
break;
|
|
718
814
|
} else {
|
|
719
|
-
|
|
815
|
+
params.push({ name: param.name });
|
|
720
816
|
}
|
|
721
817
|
} else {
|
|
722
|
-
params.push({
|
|
818
|
+
params.push({ value: param });
|
|
723
819
|
}
|
|
724
820
|
} else {
|
|
725
|
-
|
|
821
|
+
break;
|
|
726
822
|
}
|
|
727
|
-
|
|
823
|
+
} while ($(','))
|
|
824
|
+
|
|
825
|
+
expect(')');
|
|
826
|
+
|
|
827
|
+
if ($(/^when/)) { // Guard
|
|
828
|
+
cond = expect(this.conditions, 'expected condition');
|
|
728
829
|
}
|
|
729
|
-
if (! $(')')) throw new(Error)("Expected )");
|
|
730
830
|
|
|
731
831
|
ruleset = $(this.block);
|
|
732
832
|
|
|
733
833
|
if (ruleset) {
|
|
734
|
-
return new(tree.mixin.Definition)(name, params, ruleset);
|
|
834
|
+
return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
|
|
835
|
+
} else {
|
|
836
|
+
restore();
|
|
735
837
|
}
|
|
736
838
|
}
|
|
737
839
|
}
|
|
@@ -766,7 +868,7 @@ less.Parser = function Parser(env) {
|
|
|
766
868
|
|
|
767
869
|
if (! $(/^\(opacity=/i)) return;
|
|
768
870
|
if (value = $(/^\d+/) || $(this.entities.variable)) {
|
|
769
|
-
|
|
871
|
+
expect(')');
|
|
770
872
|
return new(tree.Alpha)(value);
|
|
771
873
|
}
|
|
772
874
|
},
|
|
@@ -784,12 +886,21 @@ less.Parser = function Parser(env) {
|
|
|
784
886
|
// and an element name, such as a tag a class, or `*`.
|
|
785
887
|
//
|
|
786
888
|
element: function () {
|
|
787
|
-
var e, t, c;
|
|
889
|
+
var e, t, c, v;
|
|
788
890
|
|
|
789
891
|
c = $(this.combinator);
|
|
790
|
-
e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
|
|
892
|
+
e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
|
|
893
|
+
$('*') || $(this.attribute) || $(/^\([^)@]+\)/);
|
|
791
894
|
|
|
792
|
-
if (e) {
|
|
895
|
+
if (! e) {
|
|
896
|
+
$('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
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
|
+
}
|
|
793
904
|
},
|
|
794
905
|
|
|
795
906
|
//
|
|
@@ -804,14 +915,18 @@ less.Parser = function Parser(env) {
|
|
|
804
915
|
combinator: function () {
|
|
805
916
|
var match, c = input.charAt(i);
|
|
806
917
|
|
|
807
|
-
if (c === '>' || c === '
|
|
918
|
+
if (c === '>' || c === '+' || c === '~') {
|
|
808
919
|
i++;
|
|
809
920
|
while (input.charAt(i) === ' ') { i++ }
|
|
810
921
|
return new(tree.Combinator)(c);
|
|
811
|
-
} else if (c === '
|
|
812
|
-
|
|
922
|
+
} else if (c === '&') {
|
|
923
|
+
match = '&';
|
|
924
|
+
i++;
|
|
925
|
+
if(input.charAt(i) === ' ') {
|
|
926
|
+
match = '& ';
|
|
927
|
+
}
|
|
813
928
|
while (input.charAt(i) === ' ') { i++ }
|
|
814
|
-
return new(tree.Combinator)(
|
|
929
|
+
return new(tree.Combinator)(match);
|
|
815
930
|
} else if (input.charAt(i - 1) === ' ') {
|
|
816
931
|
return new(tree.Combinator)(" ");
|
|
817
932
|
} else {
|
|
@@ -830,6 +945,12 @@ less.Parser = function Parser(env) {
|
|
|
830
945
|
selector: function () {
|
|
831
946
|
var sel, e, elements = [], c, match;
|
|
832
947
|
|
|
948
|
+
if ($('(')) {
|
|
949
|
+
sel = $(this.entity);
|
|
950
|
+
expect(')');
|
|
951
|
+
return new(tree.Selector)([new(tree.Element)('', sel, i)]);
|
|
952
|
+
}
|
|
953
|
+
|
|
833
954
|
while (e = $(this.element)) {
|
|
834
955
|
c = input.charAt(i);
|
|
835
956
|
elements.push(e)
|
|
@@ -877,20 +998,15 @@ less.Parser = function Parser(env) {
|
|
|
877
998
|
var selectors = [], s, rules, match;
|
|
878
999
|
save();
|
|
879
1000
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
selectors.push(s);
|
|
886
|
-
$(this.comment);
|
|
887
|
-
if (! $(',')) { break }
|
|
888
|
-
$(this.comment);
|
|
889
|
-
}
|
|
1001
|
+
while (s = $(this.selector)) {
|
|
1002
|
+
selectors.push(s);
|
|
1003
|
+
$(this.comment);
|
|
1004
|
+
if (! $(',')) { break }
|
|
1005
|
+
$(this.comment);
|
|
890
1006
|
}
|
|
891
1007
|
|
|
892
1008
|
if (selectors.length > 0 && (rules = $(this.block))) {
|
|
893
|
-
return new(tree.Ruleset)(selectors, rules);
|
|
1009
|
+
return new(tree.Ruleset)(selectors, rules, env.strictImports);
|
|
894
1010
|
} else {
|
|
895
1011
|
// Backtrack
|
|
896
1012
|
furthest = i;
|
|
@@ -934,11 +1050,67 @@ less.Parser = function Parser(env) {
|
|
|
934
1050
|
// stored in `import`, which we pass to the Import constructor.
|
|
935
1051
|
//
|
|
936
1052
|
"import": function () {
|
|
937
|
-
var path;
|
|
1053
|
+
var path, features, index = i;
|
|
938
1054
|
if ($(/^@import\s+/) &&
|
|
939
|
-
(path = $(this.entities.quoted) || $(this.entities.url))
|
|
940
|
-
$(
|
|
941
|
-
|
|
1055
|
+
(path = $(this.entities.quoted) || $(this.entities.url))) {
|
|
1056
|
+
features = $(this.mediaFeatures);
|
|
1057
|
+
if ($(';')) {
|
|
1058
|
+
return new(tree.Import)(path, imports, features, index);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
|
|
1063
|
+
mediaFeature: function () {
|
|
1064
|
+
var e, p, nodes = [];
|
|
1065
|
+
|
|
1066
|
+
do {
|
|
1067
|
+
if (e = $(this.entities.keyword)) {
|
|
1068
|
+
nodes.push(e);
|
|
1069
|
+
} else if ($('(')) {
|
|
1070
|
+
p = $(this.property);
|
|
1071
|
+
e = $(this.entity);
|
|
1072
|
+
if ($(')')) {
|
|
1073
|
+
if (p && e) {
|
|
1074
|
+
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
|
|
1075
|
+
} else if (e) {
|
|
1076
|
+
nodes.push(new(tree.Paren)(e));
|
|
1077
|
+
} else {
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
} else { return null }
|
|
1081
|
+
}
|
|
1082
|
+
} while (e);
|
|
1083
|
+
|
|
1084
|
+
if (nodes.length > 0) {
|
|
1085
|
+
return new(tree.Expression)(nodes);
|
|
1086
|
+
}
|
|
1087
|
+
},
|
|
1088
|
+
|
|
1089
|
+
mediaFeatures: function () {
|
|
1090
|
+
var e, features = [];
|
|
1091
|
+
|
|
1092
|
+
do {
|
|
1093
|
+
if (e = $(this.mediaFeature)) {
|
|
1094
|
+
features.push(e);
|
|
1095
|
+
if (! $(',')) { break }
|
|
1096
|
+
} else if (e = $(this.entities.variable)) {
|
|
1097
|
+
features.push(e);
|
|
1098
|
+
if (! $(',')) { break }
|
|
1099
|
+
}
|
|
1100
|
+
} while (e);
|
|
1101
|
+
|
|
1102
|
+
return features.length > 0 ? features : null;
|
|
1103
|
+
},
|
|
1104
|
+
|
|
1105
|
+
media: function () {
|
|
1106
|
+
var features, rules;
|
|
1107
|
+
|
|
1108
|
+
if ($(/^@media/)) {
|
|
1109
|
+
features = $(this.mediaFeatures);
|
|
1110
|
+
|
|
1111
|
+
if (rules = $(this.block)) {
|
|
1112
|
+
return new(tree.Media)(rules, features);
|
|
1113
|
+
}
|
|
942
1114
|
}
|
|
943
1115
|
},
|
|
944
1116
|
|
|
@@ -948,13 +1120,13 @@ less.Parser = function Parser(env) {
|
|
|
948
1120
|
// @charset "utf-8";
|
|
949
1121
|
//
|
|
950
1122
|
directive: function () {
|
|
951
|
-
var name, value, rules, types;
|
|
1123
|
+
var name, value, rules, types, e, nodes;
|
|
952
1124
|
|
|
953
1125
|
if (input.charAt(i) !== '@') return;
|
|
954
1126
|
|
|
955
|
-
if (value = $(this['import'])) {
|
|
1127
|
+
if (value = $(this['import']) || $(this.media)) {
|
|
956
1128
|
return value;
|
|
957
|
-
} else if (name = $(/^@
|
|
1129
|
+
} else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
|
|
958
1130
|
types = ($(/^[^{]+/) || '').trim();
|
|
959
1131
|
if (rules = $(this.block)) {
|
|
960
1132
|
return new(tree.Directive)(name + " " + types, rules);
|
|
@@ -1021,7 +1193,7 @@ less.Parser = function Parser(env) {
|
|
|
1021
1193
|
multiplication: function () {
|
|
1022
1194
|
var m, a, op, operation;
|
|
1023
1195
|
if (m = $(this.operand)) {
|
|
1024
|
-
while ((op = ($('/') || $('*'))) && (a = $(this.operand))) {
|
|
1196
|
+
while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
|
|
1025
1197
|
operation = new(tree.Operation)(op, [operation || m, a]);
|
|
1026
1198
|
}
|
|
1027
1199
|
return operation || m;
|
|
@@ -1037,6 +1209,35 @@ less.Parser = function Parser(env) {
|
|
|
1037
1209
|
return operation || m;
|
|
1038
1210
|
}
|
|
1039
1211
|
},
|
|
1212
|
+
conditions: function () {
|
|
1213
|
+
var a, b, index = i, condition;
|
|
1214
|
+
|
|
1215
|
+
if (a = $(this.condition)) {
|
|
1216
|
+
while ($(',') && (b = $(this.condition))) {
|
|
1217
|
+
condition = new(tree.Condition)('or', condition || a, b, index);
|
|
1218
|
+
}
|
|
1219
|
+
return condition || a;
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
condition: function () {
|
|
1223
|
+
var a, b, c, op, index = i, negate = false;
|
|
1224
|
+
|
|
1225
|
+
if ($(/^not/)) { negate = true }
|
|
1226
|
+
expect('(');
|
|
1227
|
+
if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
|
|
1228
|
+
if (op = $(/^(?:>=|=<|[<=>])/)) {
|
|
1229
|
+
if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
|
|
1230
|
+
c = new(tree.Condition)(op, a, b, index, negate);
|
|
1231
|
+
} else {
|
|
1232
|
+
error('expected expression');
|
|
1233
|
+
}
|
|
1234
|
+
} else {
|
|
1235
|
+
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
|
|
1236
|
+
}
|
|
1237
|
+
expect(')');
|
|
1238
|
+
return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
1040
1241
|
|
|
1041
1242
|
//
|
|
1042
1243
|
// An operand is anything that can be part of an operation,
|
|
@@ -1081,18 +1282,24 @@ less.Parser = function Parser(env) {
|
|
|
1081
1282
|
};
|
|
1082
1283
|
};
|
|
1083
1284
|
|
|
1084
|
-
if (
|
|
1285
|
+
if (less.mode === 'browser' || less.mode === 'rhino') {
|
|
1085
1286
|
//
|
|
1086
1287
|
// Used by `@import` directives
|
|
1087
1288
|
//
|
|
1088
1289
|
less.Parser.importer = function (path, paths, callback, env) {
|
|
1089
|
-
if (
|
|
1290
|
+
if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
|
|
1090
1291
|
path = paths[0] + path;
|
|
1091
1292
|
}
|
|
1092
1293
|
// We pass `true` as 3rd argument, to force the reload of the import.
|
|
1093
1294
|
// This is so we can get the syntax tree as opposed to just the CSS output,
|
|
1094
1295
|
// as we need this to evaluate the current stylesheet.
|
|
1095
|
-
loadStyleSheet({ href: path, title: path, type: env.mime },
|
|
1296
|
+
loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
|
|
1297
|
+
if (e && typeof(env.errback) === "function") {
|
|
1298
|
+
env.errback.call(null, path, paths, callback, env);
|
|
1299
|
+
} else {
|
|
1300
|
+
callback.apply(null, arguments);
|
|
1301
|
+
}
|
|
1302
|
+
}, true);
|
|
1096
1303
|
};
|
|
1097
1304
|
}
|
|
1098
1305
|
|