less 3.0.0-pre.2 → 3.0.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.
- package/.eslintrc.json +88 -0
- package/.github/stale.yml +17 -0
- package/.project +17 -0
- package/.settings/org.eclipse.buildship.core.prefs +2 -0
- package/.travis.yml +22 -3
- package/.vscode/launch.json +14 -0
- package/CHANGELOG.md +27 -0
- package/Gruntfile.js +191 -86
- package/README.md +5 -7
- package/appveyor.yml +9 -10
- package/bin/lessc +37 -50
- package/dist/less.js +1357 -1269
- package/dist/less.min.js +7 -7
- package/lib/less/contexts.js +20 -16
- package/lib/less/default-options.js +65 -0
- package/lib/less/environment/abstract-file-manager.js +13 -14
- package/lib/less/environment/abstract-plugin-loader.js +45 -36
- package/lib/less/environment/environment.js +5 -0
- package/lib/less/functions/boolean.js +15 -0
- package/lib/less/functions/color.js +54 -24
- package/lib/less/functions/data-uri.js +5 -2
- package/lib/less/functions/function-registry.js +1 -1
- package/lib/less/functions/index.js +2 -1
- package/lib/less/functions/number.js +2 -2
- package/lib/less/functions/string.js +2 -2
- package/lib/less/functions/svg.js +4 -4
- package/lib/less/import-manager.js +41 -29
- package/lib/less/index.js +28 -3
- package/lib/less/less-error.js +112 -13
- package/lib/less/parse.js +18 -15
- package/lib/less/parser/parser-input.js +4 -4
- package/lib/less/parser/parser.js +208 -114
- package/lib/less/plugin-manager.js +8 -33
- package/lib/less/render.js +6 -2
- package/lib/less/source-map-builder.js +3 -0
- package/lib/less/source-map-output.js +13 -8
- package/lib/less/transform-tree.js +2 -2
- package/lib/less/tree/anonymous.js +4 -1
- package/lib/less/tree/atrule.js +7 -6
- package/lib/less/tree/call.js +25 -3
- package/lib/less/tree/color.js +2 -2
- package/lib/less/tree/debug-info.js +1 -1
- package/lib/less/tree/declaration.js +6 -5
- package/lib/less/tree/dimension.js +4 -1
- package/lib/less/tree/extend.js +2 -2
- package/lib/less/tree/import.js +17 -9
- package/lib/less/tree/index.js +3 -7
- package/lib/less/tree/js-eval-node.js +1 -1
- package/lib/less/tree/media.js +3 -14
- package/lib/less/tree/mixin-definition.js +3 -3
- package/lib/less/tree/node.js +9 -6
- package/lib/less/tree/operation.js +1 -1
- package/lib/less/tree/property.js +70 -0
- package/lib/less/tree/quoted.js +11 -10
- package/lib/less/tree/ruleset.js +115 -71
- package/lib/less/tree/selector.js +38 -23
- package/lib/less/tree/unit.js +1 -1
- package/lib/less/tree/value.js +6 -1
- package/lib/less/tree/{ruleset-call.js → variable-call.js} +5 -5
- package/lib/less/tree/variable.js +6 -6
- package/lib/less/utils.js +40 -0
- package/lib/less/visitors/extend-visitor.js +14 -14
- package/lib/less/visitors/import-visitor.js +2 -2
- package/lib/less/visitors/join-selector-visitor.js +1 -1
- package/lib/less/visitors/to-css-visitor.js +51 -84
- package/lib/less/visitors/visitor.js +15 -15
- package/lib/less-browser/bootstrap.js +21 -5
- package/lib/less-browser/cache.js +2 -2
- package/lib/less-browser/error-reporting.js +5 -5
- package/lib/less-browser/file-manager.js +27 -35
- package/lib/less-browser/index.js +12 -17
- package/lib/less-browser/plugin-loader.js +8 -45
- package/lib/less-browser/utils.js +1 -1
- package/lib/less-node/file-manager.js +99 -69
- package/lib/less-node/fs.js +1 -1
- package/lib/less-node/image-size.js +2 -2
- package/lib/less-node/index.js +7 -57
- package/lib/less-node/lessc-helper.js +38 -38
- package/lib/less-node/plugin-loader.js +18 -79
- package/lib/less-node/url-file-manager.js +1 -1
- package/lib/less-rhino/index.js +29 -44
- package/package.json +16 -9
- package/test/browser/common.js +54 -18
- package/test/browser/css/plugin/plugin.css +3 -0
- package/test/browser/jasmine-jsreporter.js +4 -4
- package/test/browser/less/plugin/plugin.js +7 -0
- package/test/browser/less/plugin/plugin.less +4 -0
- package/test/browser/less.js +11685 -13
- package/test/browser/runner-browser-options.js +6 -1
- package/test/browser/runner-filemanagerPlugin-options.js +3 -2
- package/test/browser/runner-legacy-options.js +2 -1
- package/test/browser/runner-main-options.js +0 -1
- package/test/browser/runner-modify-vars-spec.js +2 -2
- package/test/browser/test-runner-template.tmpl +38 -14
- package/test/copy-bom.js +1 -1
- package/test/css/calc.css +5 -0
- package/test/css/comments2.css +1 -1
- package/test/css/compression/compression.css +1 -1
- package/test/css/css-grid.css +11 -0
- package/test/css/debug/linenumbers-all.css +0 -1
- package/test/css/debug/linenumbers-comments.css +0 -1
- package/test/css/debug/linenumbers-mediaquery.css +0 -1
- package/test/css/functions.css +16 -3
- package/test/css/import-module.css +9 -0
- package/test/css/import.css +0 -1
- package/test/css/legacy/legacy.css +1 -1
- package/test/css/merge.css +5 -4
- package/test/css/plugin-module.css +1 -0
- package/test/css/plugin.css +20 -0
- package/test/css/property-accessors.css +49 -0
- package/test/css/{css.css → strict-math/css.css} +0 -0
- package/test/css/{mixins-args.css → strict-math/mixins-args.css} +0 -0
- package/test/css/{parens.css → strict-math/parens.css} +0 -0
- package/test/import-module/one/1.less +3 -0
- package/test/import-module/one/two/2.less +3 -0
- package/test/import-module/one/two/three/3.less +3 -0
- package/test/import-module/package.json +11 -0
- package/test/index.js +55 -49
- package/test/less/calc.less +7 -0
- package/test/less/css-grid.less +15 -0
- package/test/less/detached-rulesets.less +2 -2
- package/test/less/errors/color-invalid-hex-code.less +1 -0
- package/test/less/errors/color-invalid-hex-code.txt +1 -1
- package/test/less/errors/color-invalid-hex-code2.less +1 -0
- package/test/less/errors/color-invalid-hex-code2.txt +1 -1
- package/test/less/errors/import-missing.txt +1 -1
- package/test/less/errors/plugin/plugin-error-2.js +5 -0
- package/test/less/errors/plugin/plugin-error-3.js +5 -0
- package/test/less/errors/plugin/plugin-error.js +1 -0
- package/test/less/errors/plugin-1.less +1 -0
- package/test/less/errors/plugin-1.txt +2 -0
- package/test/less/errors/plugin-2.less +1 -0
- package/test/less/errors/plugin-2.txt +5 -0
- package/test/less/errors/plugin-3.less +1 -0
- package/test/less/errors/plugin-3.txt +5 -0
- package/test/less/functions.less +18 -0
- package/test/less/import-module.less +3 -0
- package/test/less/import.less +0 -2
- package/test/less/legacy/legacy.less +1 -1
- package/test/less/media.less +2 -2
- package/test/less/merge.less +6 -3
- package/test/less/plugin/plugin-collection.js +9 -0
- package/test/less/plugin/plugin-local.js +2 -2
- package/test/less/plugin/plugin-scope1.js +3 -0
- package/test/less/plugin/plugin-scope2.js +3 -0
- package/test/less/plugin/plugin-simple.js +7 -0
- package/test/less/plugin/plugin-tree-nodes.js +33 -31
- package/test/less/plugin-module.less +7 -0
- package/test/less/plugin.less +33 -3
- package/test/less/property-accessors.less +67 -0
- package/test/less/root-registry/file.less +1 -0
- package/test/less/root-registry/root.less +3 -0
- package/test/less/{css.less → strict-math/css.less} +0 -0
- package/test/less/{mixins-args.less → strict-math/mixins-args.less} +0 -0
- package/test/less/{parens.less → strict-math/parens.less} +0 -0
- package/test/less-bom/calc.less +7 -0
- package/test/less-bom/css-grid.less +15 -0
- package/test/less-bom/detached-rulesets.less +2 -2
- package/test/less-bom/errors/color-invalid-hex-code.less +1 -0
- package/test/less-bom/errors/color-invalid-hex-code.txt +1 -1
- package/test/less-bom/errors/color-invalid-hex-code2.less +1 -0
- package/test/less-bom/errors/color-invalid-hex-code2.txt +1 -1
- package/test/less-bom/errors/import-missing.txt +1 -1
- package/test/less-bom/errors/plugin/plugin-error-2.js +5 -0
- package/test/less-bom/errors/plugin/plugin-error-3.js +5 -0
- package/test/less-bom/errors/plugin/plugin-error.js +1 -0
- package/test/less-bom/errors/plugin-1.less +1 -0
- package/test/less-bom/errors/plugin-1.txt +2 -0
- package/test/less-bom/errors/plugin-2.less +1 -0
- package/test/less-bom/errors/plugin-2.txt +5 -0
- package/test/less-bom/errors/plugin-3.less +1 -0
- package/test/less-bom/errors/plugin-3.txt +5 -0
- package/test/less-bom/functions.less +18 -0
- package/test/less-bom/import-module.less +3 -0
- package/test/less-bom/import.less +0 -2
- package/test/less-bom/legacy/legacy.less +1 -1
- package/test/less-bom/media.less +2 -2
- package/test/less-bom/merge.less +6 -3
- package/test/less-bom/plugin/plugin-collection.js +9 -0
- package/test/less-bom/plugin/plugin-local.js +2 -2
- package/test/less-bom/plugin/plugin-scope1.js +3 -0
- package/test/less-bom/plugin/plugin-scope2.js +3 -0
- package/test/less-bom/plugin/plugin-simple.js +7 -0
- package/test/less-bom/plugin/plugin-tree-nodes.js +33 -31
- package/test/less-bom/plugin-module.less +7 -0
- package/test/less-bom/plugin.less +33 -3
- package/test/less-bom/property-accessors.less +67 -0
- package/test/less-bom/root-registry/file.less +1 -0
- package/test/less-bom/root-registry/root.less +3 -0
- package/test/less-bom/{css.less → strict-math/css.less} +0 -0
- package/test/less-bom/{mixins-args.less → strict-math/mixins-args.less} +0 -0
- package/test/less-bom/{parens.less → strict-math/parens.less} +0 -0
- package/test/less-test.js +75 -17
- package/test/modify-vars.js +1 -1
- package/test/plugins/visitor/index.js +1 -1
- package/.jscsrc +0 -73
- package/.jshintrc +0 -11
- package/lib/less/tree/alpha.js +0 -28
- package/lib/less/tree/directive.js +0 -12
- package/lib/less/tree/rule.js +0 -12
- package/test/less/errors/functions-2-alpha.less +0 -2
- package/test/less/errors/functions-2-alpha.txt +0 -3
- package/test/less-bom/errors/functions-2-alpha.less +0 -2
- package/test/less-bom/errors/functions-2-alpha.txt +0 -3
- package/test/sourcemaps/maps/import-map.map +0 -1
|
@@ -2,7 +2,8 @@ var LessError = require('../less-error'),
|
|
|
2
2
|
tree = require("../tree"),
|
|
3
3
|
visitors = require("../visitors"),
|
|
4
4
|
getParserInput = require("./parser-input"),
|
|
5
|
-
utils = require("../utils")
|
|
5
|
+
utils = require("../utils"),
|
|
6
|
+
functionRegistry = require('../functions/function-registry');
|
|
6
7
|
|
|
7
8
|
//
|
|
8
9
|
// less.js - parser
|
|
@@ -35,8 +36,8 @@ var LessError = require('../less-error'),
|
|
|
35
36
|
// Token matching is done with the `$` function, which either takes
|
|
36
37
|
// a terminal string or regexp, or a non-terminal function to call.
|
|
37
38
|
// It also takes care of moving all the indices forwards.
|
|
38
|
-
//`
|
|
39
39
|
//
|
|
40
|
+
|
|
40
41
|
var Parser = function Parser(context, imports, fileInfo) {
|
|
41
42
|
var parsers,
|
|
42
43
|
parserInput = getParserInput();
|
|
@@ -80,11 +81,61 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
80
81
|
};
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Used after initial parsing to create nodes on the fly
|
|
86
|
+
*
|
|
87
|
+
* @param {String} str - string to parse
|
|
88
|
+
* @param {Array} parseList - array of parsers to run input through e.g. ["value", "important"]
|
|
89
|
+
* @param {Number} currentIndex - start number to begin indexing
|
|
90
|
+
* @param {Object} fileInfo - fileInfo to attach to created nodes
|
|
91
|
+
*/
|
|
92
|
+
function parseNode(str, parseList, currentIndex, fileInfo, callback) {
|
|
93
|
+
var result, returnNodes = [];
|
|
94
|
+
var parser = parserInput;
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
parser.start(str, false, function fail(msg, index) {
|
|
98
|
+
callback({
|
|
99
|
+
message: msg,
|
|
100
|
+
index: index + currentIndex
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
for (var x = 0, p, i; (p = parseList[x]); x++) {
|
|
104
|
+
i = parser.i;
|
|
105
|
+
result = parsers[p]();
|
|
106
|
+
if (result) {
|
|
107
|
+
result._index = i + currentIndex;
|
|
108
|
+
result._fileInfo = fileInfo;
|
|
109
|
+
returnNodes.push(result);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
returnNodes.push(null);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
var endInfo = parser.end();
|
|
117
|
+
if (endInfo.isFinished) {
|
|
118
|
+
callback(null, returnNodes);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
callback(true, null);
|
|
122
|
+
}
|
|
123
|
+
} catch (e) {
|
|
124
|
+
throw new LessError({
|
|
125
|
+
index: e.index + currentIndex,
|
|
126
|
+
message: e.message
|
|
127
|
+
}, imports, fileInfo.filename);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
83
131
|
//
|
|
84
132
|
// The Parser
|
|
85
133
|
//
|
|
86
134
|
return {
|
|
87
|
-
|
|
135
|
+
parserInput: parserInput,
|
|
136
|
+
imports: imports,
|
|
137
|
+
fileInfo: fileInfo,
|
|
138
|
+
parseNode: parseNode,
|
|
88
139
|
//
|
|
89
140
|
// Parse an input string into an abstract syntax tree,
|
|
90
141
|
// @param str A string containing 'less' markup
|
|
@@ -130,9 +181,13 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
130
181
|
}, imports);
|
|
131
182
|
});
|
|
132
183
|
|
|
133
|
-
|
|
184
|
+
tree.Node.prototype.parse = this;
|
|
185
|
+
root = new tree.Ruleset(null, this.parsers.primary());
|
|
186
|
+
tree.Node.prototype.rootNode = root;
|
|
134
187
|
root.root = true;
|
|
135
188
|
root.firstRoot = true;
|
|
189
|
+
root.functionRegistry = functionRegistry.inherit();
|
|
190
|
+
|
|
136
191
|
} catch (e) {
|
|
137
192
|
return callback(new LessError(e, imports, fileInfo.filename));
|
|
138
193
|
}
|
|
@@ -261,7 +316,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
261
316
|
}
|
|
262
317
|
|
|
263
318
|
node = mixin.definition() || this.declaration() || this.ruleset() ||
|
|
264
|
-
mixin.call() || this.
|
|
319
|
+
mixin.call() || this.variableCall() || this.entities.call() || this.atrule();
|
|
265
320
|
if (node) {
|
|
266
321
|
root.push(node);
|
|
267
322
|
} else {
|
|
@@ -319,7 +374,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
319
374
|
// black border-collapse
|
|
320
375
|
//
|
|
321
376
|
keyword: function () {
|
|
322
|
-
var k = parserInput.$char("%") || parserInput.$re(
|
|
377
|
+
var k = parserInput.$char("%") || parserInput.$re(/^\[?[_A-Za-z-][_A-Za-z0-9-]*\]?/);
|
|
323
378
|
if (k) {
|
|
324
379
|
return tree.Color.fromKeyword(k) || new(tree.Keyword)(k);
|
|
325
380
|
}
|
|
@@ -330,13 +385,10 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
330
385
|
//
|
|
331
386
|
// rgb(255, 0, 255)
|
|
332
387
|
//
|
|
333
|
-
// We also try to catch IE's `alpha()`, but let the `alpha` parser
|
|
334
|
-
// deal with the details.
|
|
335
|
-
//
|
|
336
388
|
// The arguments are parsed with the `entities.arguments` parser.
|
|
337
389
|
//
|
|
338
390
|
call: function () {
|
|
339
|
-
var name,
|
|
391
|
+
var name, args, func, index = parserInput.i;
|
|
340
392
|
|
|
341
393
|
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
|
342
394
|
if (parserInput.peek(/^url\(/i)) {
|
|
@@ -346,70 +398,98 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
346
398
|
parserInput.save();
|
|
347
399
|
|
|
348
400
|
name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/);
|
|
349
|
-
if (!name) {
|
|
401
|
+
if (!name) {
|
|
402
|
+
parserInput.forget();
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
350
405
|
|
|
351
406
|
name = name[1];
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (alpha) {
|
|
407
|
+
func = this.customFuncCall(name);
|
|
408
|
+
if (func) {
|
|
409
|
+
args = func.parse();
|
|
410
|
+
if (args && func.stop) {
|
|
357
411
|
parserInput.forget();
|
|
358
|
-
return
|
|
412
|
+
return args;
|
|
359
413
|
}
|
|
360
414
|
}
|
|
361
415
|
|
|
362
|
-
args = this.arguments();
|
|
416
|
+
args = this.arguments(args);
|
|
363
417
|
|
|
364
|
-
if (!
|
|
418
|
+
if (!parserInput.$char(')')) {
|
|
365
419
|
parserInput.restore("Could not parse call arguments or missing ')'");
|
|
366
420
|
return;
|
|
367
421
|
}
|
|
368
422
|
|
|
369
423
|
parserInput.forget();
|
|
424
|
+
|
|
370
425
|
return new(tree.Call)(name, args, index, fileInfo);
|
|
371
426
|
},
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
427
|
+
|
|
428
|
+
//
|
|
429
|
+
// Parsing rules for functions with non-standard args, e.g.:
|
|
430
|
+
//
|
|
431
|
+
// boolean(not(2 > 1))
|
|
432
|
+
//
|
|
433
|
+
// This is a quick prototype, to be modified/improved when
|
|
434
|
+
// more custom-parsed funcs come (e.g. `selector(...)`)
|
|
435
|
+
//
|
|
378
436
|
|
|
379
|
-
|
|
437
|
+
customFuncCall: function (name) {
|
|
438
|
+
/* Ideally the table is to be moved out of here for faster perf.,
|
|
439
|
+
but it's quite tricky since it relies on all these `parsers`
|
|
440
|
+
and `expect` available only here */
|
|
441
|
+
return {
|
|
442
|
+
alpha: f(parsers.ieAlpha, true),
|
|
443
|
+
boolean: f(condition),
|
|
444
|
+
'if': f(condition)
|
|
445
|
+
}[name.toLowerCase()];
|
|
446
|
+
|
|
447
|
+
function f(parse, stop) {
|
|
448
|
+
return {
|
|
449
|
+
parse: parse, // parsing function
|
|
450
|
+
stop: stop // when true - stop after parse() and return its result,
|
|
451
|
+
// otherwise continue for plain args
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function condition() {
|
|
456
|
+
return [expect(parsers.condition, 'expected condition')];
|
|
457
|
+
}
|
|
458
|
+
},
|
|
380
459
|
|
|
381
|
-
|
|
460
|
+
arguments: function (prevArgs) {
|
|
461
|
+
var argsComma = prevArgs || [],
|
|
462
|
+
argsSemiColon = [],
|
|
463
|
+
isSemiColonSeparated, value;
|
|
382
464
|
|
|
383
|
-
|
|
384
|
-
break;
|
|
385
|
-
}
|
|
465
|
+
parserInput.save();
|
|
386
466
|
|
|
387
|
-
|
|
467
|
+
while (true) {
|
|
468
|
+
if (prevArgs) {
|
|
469
|
+
prevArgs = false;
|
|
470
|
+
} else {
|
|
471
|
+
value = parsers.detachedRuleset() || this.assignment() || parsers.expression();
|
|
472
|
+
if (!value) {
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
388
475
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
476
|
+
if (value.value && value.value.length == 1) {
|
|
477
|
+
value = value.value[0];
|
|
478
|
+
}
|
|
392
479
|
|
|
393
|
-
|
|
394
|
-
expressions.push(value);
|
|
480
|
+
argsComma.push(value);
|
|
395
481
|
}
|
|
396
482
|
|
|
397
|
-
argsComma.push(value);
|
|
398
|
-
|
|
399
483
|
if (parserInput.$char(',')) {
|
|
400
484
|
continue;
|
|
401
485
|
}
|
|
402
486
|
|
|
403
487
|
if (parserInput.$char(';') || isSemiColonSeparated) {
|
|
404
|
-
|
|
405
488
|
isSemiColonSeparated = true;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
value = new(tree.Value)(expressions);
|
|
409
|
-
}
|
|
489
|
+
value = (argsComma.length < 1) ? argsComma[0]
|
|
490
|
+
: new tree.Value(argsComma);
|
|
410
491
|
argsSemiColon.push(value);
|
|
411
|
-
|
|
412
|
-
expressions = [];
|
|
492
|
+
argsComma = [];
|
|
413
493
|
}
|
|
414
494
|
}
|
|
415
495
|
|
|
@@ -467,15 +547,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
467
547
|
return;
|
|
468
548
|
}
|
|
469
549
|
|
|
470
|
-
value = this.quoted() || this.variable() ||
|
|
550
|
+
value = this.quoted() || this.variable() || this.property() ||
|
|
471
551
|
parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
|
|
472
552
|
|
|
473
553
|
parserInput.autoCommentAbsorb = true;
|
|
474
554
|
|
|
475
555
|
expectChar(')');
|
|
476
556
|
|
|
477
|
-
return new(tree.URL)((value.value != null ||
|
|
478
|
-
|
|
557
|
+
return new(tree.URL)((value.value != null ||
|
|
558
|
+
value instanceof tree.Variable ||
|
|
559
|
+
value instanceof tree.Property) ?
|
|
560
|
+
value : new(tree.Anonymous)(value, index), index, fileInfo);
|
|
479
561
|
},
|
|
480
562
|
|
|
481
563
|
//
|
|
@@ -502,7 +584,27 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
502
584
|
return new(tree.Variable)("@" + curly[1], index, fileInfo);
|
|
503
585
|
}
|
|
504
586
|
},
|
|
587
|
+
//
|
|
588
|
+
// A Property accessor, such as `$color`, in
|
|
589
|
+
//
|
|
590
|
+
// background-color: $color
|
|
591
|
+
//
|
|
592
|
+
property: function () {
|
|
593
|
+
var name, index = parserInput.i;
|
|
594
|
+
|
|
595
|
+
if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) {
|
|
596
|
+
return new(tree.Property)(name, index, fileInfo);
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
|
|
600
|
+
// A property entity useing the protective {} e.g. ${prop}
|
|
601
|
+
propertyCurly: function () {
|
|
602
|
+
var curly, index = parserInput.i;
|
|
505
603
|
|
|
604
|
+
if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) {
|
|
605
|
+
return new(tree.Property)("$" + curly[1], index, fileInfo);
|
|
606
|
+
}
|
|
607
|
+
},
|
|
506
608
|
//
|
|
507
609
|
// A Hexadecimal color
|
|
508
610
|
//
|
|
@@ -612,15 +714,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
612
714
|
},
|
|
613
715
|
|
|
614
716
|
//
|
|
615
|
-
//
|
|
717
|
+
// Call a variable value
|
|
616
718
|
//
|
|
617
|
-
// @fink()
|
|
719
|
+
// @fink()
|
|
618
720
|
//
|
|
619
|
-
|
|
721
|
+
variableCall: function () {
|
|
620
722
|
var name;
|
|
621
723
|
|
|
622
|
-
if (parserInput.currentChar() === '@'
|
|
623
|
-
|
|
724
|
+
if (parserInput.currentChar() === '@'
|
|
725
|
+
&& (name = parserInput.$re(/^(@[\w-]+)\(\s*\)/))
|
|
726
|
+
&& parsers.end()) {
|
|
727
|
+
return new tree.VariableCall(name[1]);
|
|
624
728
|
}
|
|
625
729
|
},
|
|
626
730
|
|
|
@@ -637,7 +741,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
637
741
|
do {
|
|
638
742
|
option = null;
|
|
639
743
|
elements = null;
|
|
640
|
-
while (!
|
|
744
|
+
while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) {
|
|
641
745
|
e = this.element();
|
|
642
746
|
if (!e) {
|
|
643
747
|
break;
|
|
@@ -756,7 +860,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
756
860
|
.push({ variadic: true });
|
|
757
861
|
break;
|
|
758
862
|
}
|
|
759
|
-
arg = entities.variable() || entities.literal() || entities.keyword();
|
|
863
|
+
arg = entities.variable() || entities.property() || entities.literal() || entities.keyword();
|
|
760
864
|
}
|
|
761
865
|
|
|
762
866
|
if (!arg) {
|
|
@@ -779,7 +883,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
779
883
|
val = arg;
|
|
780
884
|
}
|
|
781
885
|
|
|
782
|
-
if (val && val instanceof tree.Variable) {
|
|
886
|
+
if (val && (val instanceof tree.Variable || val instanceof tree.Property)) {
|
|
783
887
|
if (parserInput.$char(':')) {
|
|
784
888
|
if (expressions.length > 0) {
|
|
785
889
|
if (isSemiColonSeparated) {
|
|
@@ -925,7 +1029,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
925
1029
|
var entities = this.entities;
|
|
926
1030
|
|
|
927
1031
|
return this.comment() || entities.literal() || entities.variable() || entities.url() ||
|
|
928
|
-
entities.call()
|
|
1032
|
+
entities.property() || entities.call() || entities.keyword() || entities.javascript();
|
|
929
1033
|
},
|
|
930
1034
|
|
|
931
1035
|
//
|
|
@@ -942,17 +1046,18 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
942
1046
|
//
|
|
943
1047
|
// alpha(opacity=88)
|
|
944
1048
|
//
|
|
945
|
-
|
|
1049
|
+
ieAlpha: function () {
|
|
946
1050
|
var value;
|
|
947
1051
|
|
|
948
1052
|
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
|
949
|
-
if (!
|
|
1053
|
+
if (!parserInput.$re(/^opacity=/i)) { return; }
|
|
950
1054
|
value = parserInput.$re(/^\d+/);
|
|
951
1055
|
if (!value) {
|
|
952
|
-
value = expect(
|
|
1056
|
+
value = expect(parsers.entities.variable, "Could not parse alpha");
|
|
1057
|
+
value = '@{' + value.name.slice(1) + '}';
|
|
953
1058
|
}
|
|
954
1059
|
expectChar(')');
|
|
955
|
-
return new
|
|
1060
|
+
return new tree.Quoted('', 'alpha(opacity=' + value + ')');
|
|
956
1061
|
},
|
|
957
1062
|
|
|
958
1063
|
//
|
|
@@ -978,10 +1083,10 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
978
1083
|
parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
|
|
979
1084
|
this.entities.variableCurly();
|
|
980
1085
|
|
|
981
|
-
if (!
|
|
1086
|
+
if (!e) {
|
|
982
1087
|
parserInput.save();
|
|
983
1088
|
if (parserInput.$char('(')) {
|
|
984
|
-
if ((v = this.selector()) && parserInput.$char(')')) {
|
|
1089
|
+
if ((v = this.selector(false)) && parserInput.$char(')')) {
|
|
985
1090
|
e = new(tree.Paren)(v);
|
|
986
1091
|
parserInput.forget();
|
|
987
1092
|
} else {
|
|
@@ -1032,14 +1137,8 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1032
1137
|
}
|
|
1033
1138
|
},
|
|
1034
1139
|
//
|
|
1035
|
-
// A CSS selector (see selector below)
|
|
1036
|
-
// with less extensions e.g. the ability to extend and guard
|
|
1037
|
-
//
|
|
1038
|
-
lessSelector: function () {
|
|
1039
|
-
return this.selector(true);
|
|
1040
|
-
},
|
|
1041
|
-
//
|
|
1042
1140
|
// A CSS Selector
|
|
1141
|
+
// with less extensions e.g. the ability to extend and guard
|
|
1043
1142
|
//
|
|
1044
1143
|
// .class > div + h1
|
|
1045
1144
|
// li a:hover
|
|
@@ -1048,7 +1147,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1048
1147
|
//
|
|
1049
1148
|
selector: function (isLess) {
|
|
1050
1149
|
var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition;
|
|
1051
|
-
|
|
1150
|
+
isLess = isLess !== false;
|
|
1052
1151
|
while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str("when"))) || (e = this.element())) {
|
|
1053
1152
|
if (when) {
|
|
1054
1153
|
condition = expect(this.conditions, 'expected condition');
|
|
@@ -1079,7 +1178,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1079
1178
|
if (allExtends) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
|
|
1080
1179
|
},
|
|
1081
1180
|
attribute: function () {
|
|
1082
|
-
if (!
|
|
1181
|
+
if (!parserInput.$char('[')) { return; }
|
|
1083
1182
|
|
|
1084
1183
|
var entities = this.entities,
|
|
1085
1184
|
key, val, op;
|
|
@@ -1138,7 +1237,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1138
1237
|
}
|
|
1139
1238
|
|
|
1140
1239
|
while (true) {
|
|
1141
|
-
s = this.
|
|
1240
|
+
s = this.selector();
|
|
1142
1241
|
if (!s) {
|
|
1143
1242
|
break;
|
|
1144
1243
|
}
|
|
@@ -1151,7 +1250,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1151
1250
|
if (s.condition && selectors.length > 1) {
|
|
1152
1251
|
error("Guards are only currently allowed on a single selector.");
|
|
1153
1252
|
}
|
|
1154
|
-
if (!
|
|
1253
|
+
if (!parserInput.$char(',')) { break; }
|
|
1155
1254
|
if (s.condition) {
|
|
1156
1255
|
error("Guards are only currently allowed on a single selector.");
|
|
1157
1256
|
}
|
|
@@ -1169,7 +1268,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1169
1268
|
parserInput.restore();
|
|
1170
1269
|
}
|
|
1171
1270
|
},
|
|
1172
|
-
declaration: function (
|
|
1271
|
+
declaration: function () {
|
|
1173
1272
|
var name, value, startOfRule = parserInput.i, c = parserInput.currentChar(), important, merge, isVariable;
|
|
1174
1273
|
|
|
1175
1274
|
if (c === '.' || c === '#' || c === '&' || c === ':') { return; }
|
|
@@ -1191,22 +1290,16 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1191
1290
|
// where each item is a tree.Keyword or tree.Variable
|
|
1192
1291
|
merge = !isVariable && name.length > 1 && name.pop().value;
|
|
1193
1292
|
|
|
1194
|
-
//
|
|
1195
|
-
//
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1293
|
+
// Try to store values as anonymous
|
|
1294
|
+
// If we need the value later we'll re-parse it in ruleset.parseValue
|
|
1295
|
+
value = this.anonymousValue();
|
|
1296
|
+
if (value) {
|
|
1297
|
+
parserInput.forget();
|
|
1298
|
+
// anonymous values absorb the end ';' which is required for them to work
|
|
1299
|
+
return new (tree.Declaration)(name, value, false, merge, startOfRule, fileInfo);
|
|
1200
1300
|
}
|
|
1301
|
+
|
|
1201
1302
|
if (!value) {
|
|
1202
|
-
value = this.anonymousValue();
|
|
1203
|
-
if (value) {
|
|
1204
|
-
parserInput.forget();
|
|
1205
|
-
// anonymous values absorb the end ';' which is required for them to work
|
|
1206
|
-
return new (tree.Declaration)(name, value, false, merge, startOfRule, fileInfo);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
if (!tryValueFirst && !value) {
|
|
1210
1303
|
value = this.value();
|
|
1211
1304
|
}
|
|
1212
1305
|
|
|
@@ -1216,20 +1309,19 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1216
1309
|
if (value && this.end()) {
|
|
1217
1310
|
parserInput.forget();
|
|
1218
1311
|
return new (tree.Declaration)(name, value, important, merge, startOfRule, fileInfo);
|
|
1219
|
-
}
|
|
1312
|
+
}
|
|
1313
|
+
else {
|
|
1220
1314
|
parserInput.restore();
|
|
1221
|
-
if (value && !tryAnonymous) {
|
|
1222
|
-
return this.declaration(true);
|
|
1223
|
-
}
|
|
1224
1315
|
}
|
|
1225
1316
|
} else {
|
|
1226
|
-
parserInput.
|
|
1317
|
+
parserInput.restore();
|
|
1227
1318
|
}
|
|
1228
1319
|
},
|
|
1229
1320
|
anonymousValue: function () {
|
|
1230
|
-
var
|
|
1321
|
+
var index = parserInput.i;
|
|
1322
|
+
var match = parserInput.$re(/^([^@\$+\/'"*`(;{}-]*);/);
|
|
1231
1323
|
if (match) {
|
|
1232
|
-
return new(tree.Anonymous)(match[1]);
|
|
1324
|
+
return new(tree.Anonymous)(match[1], index);
|
|
1233
1325
|
}
|
|
1234
1326
|
},
|
|
1235
1327
|
|
|
@@ -1272,13 +1364,13 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1272
1364
|
var o, options = {}, optionName, value;
|
|
1273
1365
|
|
|
1274
1366
|
// list of options, surrounded by parens
|
|
1275
|
-
if (!
|
|
1367
|
+
if (!parserInput.$char('(')) { return null; }
|
|
1276
1368
|
do {
|
|
1277
1369
|
o = this.importOption();
|
|
1278
1370
|
if (o) {
|
|
1279
1371
|
optionName = o;
|
|
1280
1372
|
value = true;
|
|
1281
|
-
switch(optionName) {
|
|
1373
|
+
switch (optionName) {
|
|
1282
1374
|
case "css":
|
|
1283
1375
|
optionName = "less";
|
|
1284
1376
|
value = false;
|
|
@@ -1289,7 +1381,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1289
1381
|
break;
|
|
1290
1382
|
}
|
|
1291
1383
|
options[optionName] = value;
|
|
1292
|
-
if (!
|
|
1384
|
+
if (!parserInput.$char(',')) { break; }
|
|
1293
1385
|
}
|
|
1294
1386
|
} while (o);
|
|
1295
1387
|
expectChar(')');
|
|
@@ -1339,12 +1431,12 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1339
1431
|
e = this.mediaFeature();
|
|
1340
1432
|
if (e) {
|
|
1341
1433
|
features.push(e);
|
|
1342
|
-
if (!
|
|
1434
|
+
if (!parserInput.$char(',')) { break; }
|
|
1343
1435
|
} else {
|
|
1344
1436
|
e = entities.variable();
|
|
1345
1437
|
if (e) {
|
|
1346
1438
|
features.push(e);
|
|
1347
|
-
if (!
|
|
1439
|
+
if (!parserInput.$char(',')) { break; }
|
|
1348
1440
|
}
|
|
1349
1441
|
}
|
|
1350
1442
|
} while (e);
|
|
@@ -1425,7 +1517,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1425
1517
|
pluginArgs: function() {
|
|
1426
1518
|
// list of options, surrounded by parens
|
|
1427
1519
|
parserInput.save();
|
|
1428
|
-
if (!
|
|
1520
|
+
if (!parserInput.$char('(')) {
|
|
1429
1521
|
parserInput.restore();
|
|
1430
1522
|
return null;
|
|
1431
1523
|
}
|
|
@@ -1467,7 +1559,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1467
1559
|
nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
|
|
1468
1560
|
}
|
|
1469
1561
|
|
|
1470
|
-
switch(nonVendorSpecificName) {
|
|
1562
|
+
switch (nonVendorSpecificName) {
|
|
1471
1563
|
case "@charset":
|
|
1472
1564
|
hasIdentifier = true;
|
|
1473
1565
|
hasBlock = false;
|
|
@@ -1534,18 +1626,18 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1534
1626
|
// and before the `;`.
|
|
1535
1627
|
//
|
|
1536
1628
|
value: function () {
|
|
1537
|
-
var e, expressions = [];
|
|
1629
|
+
var e, expressions = [], index = parserInput.i;
|
|
1538
1630
|
|
|
1539
1631
|
do {
|
|
1540
1632
|
e = this.expression();
|
|
1541
1633
|
if (e) {
|
|
1542
1634
|
expressions.push(e);
|
|
1543
|
-
if (!
|
|
1635
|
+
if (!parserInput.$char(',')) { break; }
|
|
1544
1636
|
}
|
|
1545
1637
|
} while (e);
|
|
1546
1638
|
|
|
1547
1639
|
if (expressions.length > 0) {
|
|
1548
|
-
return new(tree.Value)(expressions);
|
|
1640
|
+
return new(tree.Value)(expressions, index);
|
|
1549
1641
|
}
|
|
1550
1642
|
},
|
|
1551
1643
|
important: function () {
|
|
@@ -1784,13 +1876,14 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1784
1876
|
operand: function () {
|
|
1785
1877
|
var entities = this.entities, negate;
|
|
1786
1878
|
|
|
1787
|
-
if (parserInput.peek(/^-[
|
|
1879
|
+
if (parserInput.peek(/^-[@\$\(]/)) {
|
|
1788
1880
|
negate = parserInput.$char('-');
|
|
1789
1881
|
}
|
|
1790
1882
|
|
|
1791
1883
|
var o = this.sub() || entities.dimension() ||
|
|
1792
1884
|
entities.color() || entities.variable() ||
|
|
1793
|
-
entities.
|
|
1885
|
+
entities.property() || entities.call() ||
|
|
1886
|
+
entities.colorKeyword();
|
|
1794
1887
|
|
|
1795
1888
|
if (negate) {
|
|
1796
1889
|
o.parensInOp = true;
|
|
@@ -1808,7 +1901,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1808
1901
|
// @var * 2
|
|
1809
1902
|
//
|
|
1810
1903
|
expression: function () {
|
|
1811
|
-
var entities = [], e, delim;
|
|
1904
|
+
var entities = [], e, delim, index = parserInput.i;
|
|
1812
1905
|
|
|
1813
1906
|
do {
|
|
1814
1907
|
e = this.comment();
|
|
@@ -1823,7 +1916,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1823
1916
|
if (!parserInput.peek(/^\/[\/*]/)) {
|
|
1824
1917
|
delim = parserInput.$char('/');
|
|
1825
1918
|
if (delim) {
|
|
1826
|
-
entities.push(new(tree.Anonymous)(delim));
|
|
1919
|
+
entities.push(new(tree.Anonymous)(delim, index));
|
|
1827
1920
|
}
|
|
1828
1921
|
}
|
|
1829
1922
|
}
|
|
@@ -1861,7 +1954,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1861
1954
|
|
|
1862
1955
|
match(/^(\*?)/);
|
|
1863
1956
|
while (true) {
|
|
1864
|
-
if (!match(/^((?:[\w-]+)|(
|
|
1957
|
+
if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) {
|
|
1865
1958
|
break;
|
|
1866
1959
|
}
|
|
1867
1960
|
}
|
|
@@ -1877,10 +1970,11 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1877
1970
|
}
|
|
1878
1971
|
for (k = 0; k < name.length; k++) {
|
|
1879
1972
|
s = name[k];
|
|
1880
|
-
name[k] = (s.charAt(0) !== '@') ?
|
|
1973
|
+
name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?
|
|
1881
1974
|
new(tree.Keyword)(s) :
|
|
1882
|
-
|
|
1883
|
-
index[k], fileInfo)
|
|
1975
|
+
(s.charAt(0) === '@' ?
|
|
1976
|
+
new(tree.Variable)('@' + s.slice(2, -1), index[k], fileInfo) :
|
|
1977
|
+
new(tree.Property)('$' + s.slice(2, -1), index[k], fileInfo));
|
|
1884
1978
|
}
|
|
1885
1979
|
return name;
|
|
1886
1980
|
}
|