less 2.3.3 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +5 -0
- data/less.gemspec +1 -1
- data/lib/less/js/.gitattributes +9 -0
- data/lib/less/js/.gitignore +1 -0
- data/lib/less/js/.npmignore +1 -1
- data/lib/less/js/CHANGELOG.md +68 -0
- data/lib/less/js/CONTRIBUTING.md +33 -34
- data/lib/less/js/Makefile +24 -9
- data/lib/less/js/README.md +2 -2
- data/lib/less/js/bin/lessc +102 -25
- data/lib/less/js/build/amd.js +1 -1
- data/lib/less/js/build/header.js +9 -7
- data/lib/less/js/dist/less-1.3.3.js +2 -2
- data/lib/less/js/dist/less-1.3.3.min.js +2 -2
- data/lib/less/js/dist/less-1.4.0-beta.js +5830 -0
- data/lib/less/js/dist/less-1.4.0-beta.min.js +11 -0
- data/lib/less/js/dist/less-1.4.0.js +5830 -0
- data/lib/less/js/dist/less-1.4.0.min.js +11 -0
- data/lib/less/js/dist/less-1.4.1.js +5837 -0
- data/lib/less/js/dist/less-1.4.1.min.js +11 -0
- data/lib/less/js/dist/less-1.4.2.js +5837 -0
- data/lib/less/js/dist/less-1.4.2.min.js +11 -0
- data/lib/less/js/dist/less-rhino-1.4.0.js +4273 -0
- data/lib/less/js/lib/less/browser.js +131 -101
- data/lib/less/js/lib/less/env.js +105 -0
- data/lib/less/js/lib/less/extend-visitor.js +391 -0
- data/lib/less/js/lib/less/functions.js +174 -19
- data/lib/less/js/lib/less/import-visitor.js +107 -0
- data/lib/less/js/lib/less/index.js +70 -63
- data/lib/less/js/lib/less/join-selector-visitor.js +37 -0
- data/lib/less/js/lib/less/lessc_helper.js +13 -4
- data/lib/less/js/lib/less/parser.js +353 -264
- data/lib/less/js/lib/less/rhino.js +5 -2
- data/lib/less/js/lib/less/tree.js +1 -1
- data/lib/less/js/lib/less/tree/alpha.js +7 -3
- data/lib/less/js/lib/less/tree/anonymous.js +1 -0
- data/lib/less/js/lib/less/tree/assignment.js +4 -0
- data/lib/less/js/lib/less/tree/call.js +14 -8
- data/lib/less/js/lib/less/tree/color.js +50 -5
- data/lib/less/js/lib/less/tree/comment.js +1 -0
- data/lib/less/js/lib/less/tree/condition.js +35 -28
- data/lib/less/js/lib/less/tree/dimension.js +270 -16
- data/lib/less/js/lib/less/tree/directive.js +7 -2
- data/lib/less/js/lib/less/tree/element.js +57 -21
- data/lib/less/js/lib/less/tree/expression.js +29 -4
- data/lib/less/js/lib/less/tree/extend.js +43 -0
- data/lib/less/js/lib/less/tree/import.js +49 -28
- data/lib/less/js/lib/less/tree/javascript.js +1 -0
- data/lib/less/js/lib/less/tree/keyword.js +3 -2
- data/lib/less/js/lib/less/tree/media.js +20 -4
- data/lib/less/js/lib/less/tree/mixin.js +38 -18
- data/lib/less/js/lib/less/tree/negative.js +22 -0
- data/lib/less/js/lib/less/tree/operation.js +32 -17
- data/lib/less/js/lib/less/tree/paren.js +5 -1
- data/lib/less/js/lib/less/tree/quoted.js +5 -3
- data/lib/less/js/lib/less/tree/rule.js +44 -31
- data/lib/less/js/lib/less/tree/ruleset.js +50 -23
- data/lib/less/js/lib/less/tree/selector.js +49 -39
- data/lib/less/js/lib/less/tree/unicode-descriptor.js +1 -0
- data/lib/less/js/lib/less/tree/url.js +9 -5
- data/lib/less/js/lib/less/tree/value.js +4 -1
- data/lib/less/js/lib/less/tree/variable.js +4 -3
- data/lib/less/js/lib/less/visitor.js +54 -0
- data/lib/less/js/package.json +69 -19
- data/lib/less/js/test/browser-test-prepare.js +23 -6
- data/lib/less/js/test/browser/common.js +55 -3
- data/lib/less/js/test/browser/css/urls.css +13 -0
- data/lib/less/js/test/browser/less/relative-urls/urls.less +1 -1
- data/lib/less/js/test/browser/less/urls.less +16 -0
- data/lib/less/js/test/browser/phantom-runner.js +7 -5
- data/lib/less/js/test/browser/runner-browser.js +5 -1
- data/lib/less/js/test/browser/runner-errors.js +5 -0
- data/lib/less/js/test/browser/runner-legacy.js +6 -0
- data/lib/less/js/test/browser/runner-production.js +7 -0
- data/lib/less/js/test/browser/template.htm +6 -6
- data/lib/less/js/test/css/comments.css +1 -0
- data/lib/less/js/test/css/compression/compression.css +2 -0
- data/lib/less/js/test/css/css-3.css +4 -0
- data/lib/less/js/test/css/css.css +9 -3
- data/lib/less/js/test/css/extend-chaining.css +72 -0
- data/lib/less/js/test/css/extend-clearfix.css +19 -0
- data/lib/less/js/test/css/extend-exact.css +37 -0
- data/lib/less/js/test/css/extend-media.css +24 -0
- data/lib/less/js/test/css/extend-nest.css +57 -0
- data/lib/less/js/test/css/extend-selector.css +72 -0
- data/lib/less/js/test/css/extend.css +76 -0
- data/lib/less/js/test/css/functions.css +28 -0
- data/lib/less/js/test/css/import-interpolation.css +6 -0
- data/lib/less/js/test/css/import.css +18 -1
- data/lib/less/js/test/css/legacy/legacy.css +7 -0
- data/lib/less/js/test/css/media.css +9 -1
- data/lib/less/js/test/css/mixins-args.css +18 -0
- data/lib/less/js/test/css/mixins-guards.css +5 -0
- data/lib/less/js/test/css/parens.css +18 -5
- data/lib/less/js/test/css/selectors.css +14 -6
- data/lib/less/js/test/css/urls.css +17 -0
- data/lib/less/js/test/css/variables.css +22 -3
- data/lib/less/js/test/data/data-uri-fail.png +0 -0
- data/lib/less/js/test/data/image.jpg +0 -0
- data/lib/less/js/test/data/page.html +1 -0
- data/lib/less/js/test/less-test.js +41 -9
- data/lib/less/js/test/less/colors.less +4 -4
- data/lib/less/js/test/less/comments.less +2 -2
- data/lib/less/js/test/less/compression/compression.less +16 -0
- data/lib/less/js/test/less/css-3.less +5 -1
- data/lib/less/js/test/less/css.less +9 -3
- data/lib/less/js/test/less/errors/add-mixed-units.less +3 -0
- data/lib/less/js/test/less/errors/add-mixed-units.txt +2 -0
- data/lib/less/js/test/less/errors/add-mixed-units2.less +3 -0
- data/lib/less/js/test/less/errors/add-mixed-units2.txt +2 -0
- data/lib/less/js/test/less/errors/bad-variable-declaration1.txt +1 -1
- data/lib/less/js/test/less/errors/color-operation-error.less +3 -0
- data/lib/less/js/test/less/errors/color-operation-error.txt +2 -0
- data/lib/less/js/test/less/errors/comment-in-selector.txt +1 -1
- data/lib/less/js/test/less/errors/divide-mixed-units.less +3 -0
- data/lib/less/js/test/less/errors/divide-mixed-units.txt +4 -0
- data/lib/less/js/test/less/errors/extend-no-selector.less +3 -0
- data/lib/less/js/test/less/errors/extend-no-selector.txt +3 -0
- data/lib/less/js/test/less/errors/extend-not-at-end.less +3 -0
- data/lib/less/js/test/less/errors/extend-not-at-end.txt +3 -0
- data/lib/less/js/test/less/errors/import-missing.less +5 -0
- data/lib/less/js/test/less/errors/import-missing.txt +3 -3
- data/lib/less/js/test/less/errors/import-no-semi.txt +1 -1
- data/lib/less/js/test/less/errors/import-subfolder1.txt +1 -1
- data/lib/less/js/test/less/errors/import-subfolder2.txt +1 -1
- data/lib/less/js/test/less/errors/javascript-error.txt +1 -1
- data/lib/less/js/test/less/errors/mixed-mixin-definition-args-1.txt +1 -1
- data/lib/less/js/test/less/errors/mixed-mixin-definition-args-2.txt +1 -1
- data/lib/less/js/test/less/errors/mixin-not-defined.txt +1 -1
- data/lib/less/js/test/less/errors/mixin-not-matched.txt +1 -1
- data/lib/less/js/test/less/errors/mixin-not-matched2.txt +1 -1
- data/lib/less/js/test/less/errors/multiply-mixed-units.less +7 -0
- data/lib/less/js/test/less/errors/multiply-mixed-units.txt +4 -0
- data/lib/less/js/test/less/errors/parens-error-1.less +3 -0
- data/lib/less/js/test/less/errors/parens-error-1.txt +4 -0
- data/lib/less/js/test/less/errors/parens-error-2.less +3 -0
- data/lib/less/js/test/less/errors/parens-error-2.txt +4 -0
- data/lib/less/js/test/less/errors/parens-error-3.less +3 -0
- data/lib/less/js/test/less/errors/parens-error-3.txt +4 -0
- data/lib/less/js/test/less/errors/parse-error-curly-bracket.txt +1 -1
- data/lib/less/js/test/less/errors/parse-error-missing-bracket.txt +2 -1
- data/lib/less/js/test/less/errors/parse-error-with-import.txt +1 -1
- data/lib/less/js/test/less/errors/property-ie5-hack.txt +1 -1
- data/lib/less/js/test/less/errors/property-in-root.less +4 -0
- data/lib/less/js/test/less/errors/property-in-root.txt +4 -0
- data/lib/less/js/test/less/errors/property-in-root2.less +1 -0
- data/lib/less/js/test/less/errors/property-in-root2.txt +4 -0
- data/lib/less/js/test/less/errors/property-in-root3.less +4 -0
- data/lib/less/js/test/less/errors/property-in-root3.txt +3 -0
- data/lib/less/js/test/less/errors/recursive-variable.txt +1 -1
- data/lib/less/js/test/less/extend-chaining.less +79 -0
- data/lib/less/js/test/less/extend-clearfix.less +19 -0
- data/lib/less/js/test/less/extend-exact.less +46 -0
- data/lib/less/js/test/less/extend-media.less +24 -0
- data/lib/less/js/test/less/extend-nest.less +65 -0
- data/lib/less/js/test/less/extend-selector.less +84 -0
- data/lib/less/js/test/less/extend.less +81 -0
- data/lib/less/js/test/less/functions.less +37 -6
- data/lib/less/js/test/less/import-interpolation.less +8 -0
- data/lib/less/js/test/less/import-once.less +4 -4
- data/lib/less/js/test/less/import.less +11 -2
- data/lib/less/js/test/less/import/deeper/import-once-test-a.less +1 -1
- data/lib/less/js/test/less/import/import-interpolation.less +1 -0
- data/lib/less/js/test/less/import/import-interpolation2.less +5 -0
- data/lib/less/js/test/less/javascript.less +1 -1
- data/lib/less/js/test/less/legacy/legacy.less +7 -0
- data/lib/less/js/test/less/media.less +14 -3
- data/lib/less/js/test/less/mixins-args.less +43 -5
- data/lib/less/js/test/less/mixins-guards.less +13 -0
- data/lib/less/js/test/less/mixins-named-args.less +5 -5
- data/lib/less/js/test/less/mixins-nested.less +2 -2
- data/lib/less/js/test/less/mixins-pattern.less +1 -1
- data/lib/less/js/test/less/mixins.less +1 -1
- data/lib/less/js/test/less/operations.less +27 -27
- data/lib/less/js/test/less/parens.less +20 -5
- data/lib/less/js/test/less/selectors.less +14 -7
- data/lib/less/js/test/less/urls.less +24 -0
- data/lib/less/js/test/less/variables.less +42 -12
- data/lib/less/loader.rb +33 -0
- data/lib/less/version.rb +1 -1
- data/spec/less/parser_spec.rb +5 -5
- metadata +76 -6
- data/lib/less/js/build/ecma-5.js +0 -120
- data/lib/less/js/lib/less/tree/ratio.js +0 -13
@@ -0,0 +1,107 @@
|
|
1
|
+
(function (tree) {
|
2
|
+
tree.importVisitor = function(importer, finish, evalEnv) {
|
3
|
+
this._visitor = new tree.visitor(this);
|
4
|
+
this._importer = importer;
|
5
|
+
this._finish = finish;
|
6
|
+
this.env = evalEnv || new tree.evalEnv();
|
7
|
+
this.importCount = 0;
|
8
|
+
};
|
9
|
+
|
10
|
+
tree.importVisitor.prototype = {
|
11
|
+
isReplacing: true,
|
12
|
+
run: function (root) {
|
13
|
+
var error;
|
14
|
+
try {
|
15
|
+
// process the contents
|
16
|
+
this._visitor.visit(root);
|
17
|
+
}
|
18
|
+
catch(e) {
|
19
|
+
error = e;
|
20
|
+
}
|
21
|
+
|
22
|
+
this.isFinished = true;
|
23
|
+
|
24
|
+
if (this.importCount === 0) {
|
25
|
+
this._finish(error);
|
26
|
+
}
|
27
|
+
},
|
28
|
+
visitImport: function (importNode, visitArgs) {
|
29
|
+
var importVisitor = this,
|
30
|
+
evaldImportNode;
|
31
|
+
|
32
|
+
if (!importNode.css) {
|
33
|
+
|
34
|
+
try {
|
35
|
+
evaldImportNode = importNode.evalForImport(this.env);
|
36
|
+
} catch(e){
|
37
|
+
if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
|
38
|
+
// attempt to eval properly and treat as css
|
39
|
+
importNode.css = true;
|
40
|
+
// if that fails, this error will be thrown
|
41
|
+
importNode.error = e;
|
42
|
+
}
|
43
|
+
|
44
|
+
if (evaldImportNode && !evaldImportNode.css) {
|
45
|
+
importNode = evaldImportNode;
|
46
|
+
this.importCount++;
|
47
|
+
var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
|
48
|
+
this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) {
|
49
|
+
if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
|
50
|
+
if (imported && !importNode.options.multiple) { importNode.skip = imported; }
|
51
|
+
|
52
|
+
var subFinish = function(e) {
|
53
|
+
importVisitor.importCount--;
|
54
|
+
|
55
|
+
if (importVisitor.importCount === 0 && importVisitor.isFinished) {
|
56
|
+
importVisitor._finish(e);
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
60
|
+
if (root) {
|
61
|
+
importNode.root = root;
|
62
|
+
new(tree.importVisitor)(importVisitor._importer, subFinish, env)
|
63
|
+
.run(root);
|
64
|
+
} else {
|
65
|
+
subFinish();
|
66
|
+
}
|
67
|
+
});
|
68
|
+
}
|
69
|
+
}
|
70
|
+
visitArgs.visitDeeper = false;
|
71
|
+
return importNode;
|
72
|
+
},
|
73
|
+
visitRule: function (ruleNode, visitArgs) {
|
74
|
+
visitArgs.visitDeeper = false;
|
75
|
+
return ruleNode;
|
76
|
+
},
|
77
|
+
visitDirective: function (directiveNode, visitArgs) {
|
78
|
+
this.env.frames.unshift(directiveNode);
|
79
|
+
return directiveNode;
|
80
|
+
},
|
81
|
+
visitDirectiveOut: function (directiveNode) {
|
82
|
+
this.env.frames.shift();
|
83
|
+
},
|
84
|
+
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
|
85
|
+
this.env.frames.unshift(mixinDefinitionNode);
|
86
|
+
return mixinDefinitionNode;
|
87
|
+
},
|
88
|
+
visitMixinDefinitionOut: function (mixinDefinitionNode) {
|
89
|
+
this.env.frames.shift();
|
90
|
+
},
|
91
|
+
visitRuleset: function (rulesetNode, visitArgs) {
|
92
|
+
this.env.frames.unshift(rulesetNode);
|
93
|
+
return rulesetNode;
|
94
|
+
},
|
95
|
+
visitRulesetOut: function (rulesetNode) {
|
96
|
+
this.env.frames.shift();
|
97
|
+
},
|
98
|
+
visitMedia: function (mediaNode, visitArgs) {
|
99
|
+
this.env.frames.unshift(mediaNode.ruleset);
|
100
|
+
return mediaNode;
|
101
|
+
},
|
102
|
+
visitMediaOut: function (mediaNode) {
|
103
|
+
this.env.frames.shift();
|
104
|
+
}
|
105
|
+
};
|
106
|
+
|
107
|
+
})(require('./tree'));
|
@@ -1,11 +1,11 @@
|
|
1
1
|
var path = require('path'),
|
2
2
|
sys = require('util'),
|
3
3
|
url = require('url'),
|
4
|
-
|
4
|
+
request,
|
5
5
|
fs = require('fs');
|
6
6
|
|
7
7
|
var less = {
|
8
|
-
version: [1,
|
8
|
+
version: [1, 4, 2],
|
9
9
|
Parser: require('./parser').Parser,
|
10
10
|
importer: require('./parser').importer,
|
11
11
|
tree: require('./tree'),
|
@@ -54,10 +54,14 @@ var less = {
|
|
54
54
|
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
55
55
|
}
|
56
56
|
|
57
|
-
if (extract[1]) {
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
if (typeof(extract[1]) === 'string') {
|
58
|
+
var errorTxt = ctx.line + ' ';
|
59
|
+
if (extract[1]) {
|
60
|
+
errorTxt += extract[1].slice(0, ctx.column) +
|
61
|
+
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
62
|
+
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
63
|
+
}
|
64
|
+
error.push(errorTxt);
|
61
65
|
}
|
62
66
|
|
63
67
|
if (typeof(extract[2]) === 'string') {
|
@@ -67,7 +71,7 @@ var less = {
|
|
67
71
|
|
68
72
|
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
69
73
|
ctx.filename && (message += stylize(' in ', 'red') + ctx.filename +
|
70
|
-
stylize('
|
74
|
+
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey'));
|
71
75
|
|
72
76
|
message += '\n' + error;
|
73
77
|
|
@@ -85,13 +89,13 @@ var less = {
|
|
85
89
|
}
|
86
90
|
};
|
87
91
|
|
88
|
-
['color', 'directive', 'operation',
|
89
|
-
'keyword', 'variable', 'ruleset',
|
90
|
-
'selector', 'quoted', 'expression',
|
91
|
-
'call', 'url', 'alpha',
|
92
|
-
'mixin', 'comment', 'anonymous',
|
93
|
-
'javascript', 'assignment', 'condition',
|
94
|
-
'media', '
|
92
|
+
['color', 'directive', 'operation', 'dimension',
|
93
|
+
'keyword', 'variable', 'ruleset', 'element',
|
94
|
+
'selector', 'quoted', 'expression', 'rule',
|
95
|
+
'call', 'url', 'alpha', 'import',
|
96
|
+
'mixin', 'comment', 'anonymous', 'value',
|
97
|
+
'javascript', 'assignment', 'condition', 'paren',
|
98
|
+
'media', 'unicode-descriptor', 'negative', 'extend'
|
95
99
|
].forEach(function (n) {
|
96
100
|
require('./tree/' + n);
|
97
101
|
});
|
@@ -99,14 +103,22 @@ var less = {
|
|
99
103
|
|
100
104
|
var isUrlRe = /^(?:https?:)?\/\//i;
|
101
105
|
|
102
|
-
less.Parser.importer = function (file,
|
103
|
-
var pathname, dirname, data
|
106
|
+
less.Parser.importer = function (file, currentFileInfo, callback, env) {
|
107
|
+
var pathname, dirname, data,
|
108
|
+
newFileInfo = {
|
109
|
+
relativeUrls: env.relativeUrls,
|
110
|
+
entryPath: currentFileInfo.entryPath,
|
111
|
+
rootpath: currentFileInfo.rootpath,
|
112
|
+
rootFilename: currentFileInfo.rootFilename
|
113
|
+
};
|
104
114
|
|
105
115
|
function parseFile(e, data) {
|
106
|
-
if (e) return callback(e);
|
116
|
+
if (e) { return callback(e); }
|
117
|
+
|
118
|
+
env = new less.tree.parseEnv(env);
|
119
|
+
env.processImports = false;
|
107
120
|
|
108
|
-
var
|
109
|
-
j = file.lastIndexOf('/');
|
121
|
+
var j = file.lastIndexOf('/');
|
110
122
|
|
111
123
|
// Pass on an updated rootpath if path of imported file is relative and file
|
112
124
|
// is in a (sub|sup) directory
|
@@ -116,29 +128,32 @@ less.Parser.importer = function (file, paths, callback, env) {
|
|
116
128
|
// then rootpath should become 'less/module/nav/'
|
117
129
|
// - If path of imported file is '../mixins.less' and rootpath is 'less/',
|
118
130
|
// then rootpath should become 'less/../'
|
119
|
-
if(
|
120
|
-
|
131
|
+
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
132
|
+
var relativeSubDirectory = file.slice(0, j+1);
|
133
|
+
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
121
134
|
}
|
135
|
+
newFileInfo.currentDirectory = pathname.replace(/[^\\\/]*$/, "");
|
136
|
+
newFileInfo.filename = pathname;
|
122
137
|
|
123
138
|
env.contents[pathname] = data; // Updating top importing parser content cache.
|
124
|
-
|
125
|
-
|
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) {
|
139
|
+
env.currentFileInfo = newFileInfo;
|
140
|
+
new(less.Parser)(env).parse(data, function (e, root) {
|
134
141
|
callback(e, root, pathname);
|
135
142
|
});
|
136
143
|
};
|
137
144
|
|
138
145
|
var isUrl = isUrlRe.test( file );
|
139
|
-
if (isUrl || isUrlRe.test(
|
146
|
+
if (isUrl || isUrlRe.test(currentFileInfo.currentDirectory)) {
|
147
|
+
if (request === undefined) {
|
148
|
+
try { request = require('request'); }
|
149
|
+
catch(e) { request = null; }
|
150
|
+
}
|
151
|
+
if (!request) {
|
152
|
+
callback({ type: 'File', message: "optional dependency 'request' required to import over http(s)\n" });
|
153
|
+
return;
|
154
|
+
}
|
140
155
|
|
141
|
-
var urlStr = isUrl ? file : url.resolve(
|
156
|
+
var urlStr = isUrl ? file : url.resolve(currentFileInfo.currentDirectory, file),
|
142
157
|
urlObj = url.parse(urlStr),
|
143
158
|
req = {
|
144
159
|
host: urlObj.hostname,
|
@@ -146,31 +161,24 @@ less.Parser.importer = function (file, paths, callback, env) {
|
|
146
161
|
path: urlObj.pathname + (urlObj.search||'')
|
147
162
|
};
|
148
163
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
}
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
parseFile(null, body);
|
164
|
-
});
|
165
|
-
}).on('error', function (err) {
|
166
|
-
callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ err +"\n" });
|
164
|
+
request.get(urlStr, function (error, res, body) {
|
165
|
+
if (res.statusCode === 404) {
|
166
|
+
callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
|
167
|
+
return;
|
168
|
+
}
|
169
|
+
if (!body) {
|
170
|
+
sys.error( 'Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"' );
|
171
|
+
}
|
172
|
+
if (error) {
|
173
|
+
callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" });
|
174
|
+
}
|
175
|
+
pathname = urlStr;
|
176
|
+
dirname = urlObj.protocol +'//'+ urlObj.host + urlObj.pathname.replace(/[^\/]*$/, '');
|
177
|
+
parseFile(null, body);
|
167
178
|
});
|
168
|
-
|
169
179
|
} else {
|
170
180
|
|
171
|
-
|
172
|
-
// or use different approach.
|
173
|
-
var paths = [].concat(paths);
|
181
|
+
var paths = [currentFileInfo.currentDirectory].concat(env.paths);
|
174
182
|
paths.push('.');
|
175
183
|
|
176
184
|
for (var i = 0; i < paths.length; i++) {
|
@@ -183,15 +191,9 @@ less.Parser.importer = function (file, paths, callback, env) {
|
|
183
191
|
}
|
184
192
|
}
|
185
193
|
|
186
|
-
paths = paths.slice(0, paths.length - 1);
|
187
|
-
|
188
194
|
if (!pathname) {
|
189
195
|
|
190
|
-
|
191
|
-
env.errback(file, paths, callback);
|
192
|
-
} else {
|
193
|
-
callback({ type: 'File', message: "'" + file + "' wasn't found.\n" });
|
194
|
-
}
|
196
|
+
callback({ type: 'File', message: "'" + file + "' wasn't found" });
|
195
197
|
return;
|
196
198
|
}
|
197
199
|
|
@@ -210,7 +212,12 @@ less.Parser.importer = function (file, paths, callback, env) {
|
|
210
212
|
}
|
211
213
|
}
|
212
214
|
|
215
|
+
require('./env');
|
213
216
|
require('./functions');
|
214
217
|
require('./colors');
|
218
|
+
require('./visitor.js');
|
219
|
+
require('./import-visitor.js');
|
220
|
+
require('./extend-visitor.js');
|
221
|
+
require('./join-selector-visitor.js');
|
215
222
|
|
216
|
-
for (var k in less) { exports[k] = less[k] }
|
223
|
+
for (var k in less) { exports[k] = less[k]; }
|
@@ -0,0 +1,37 @@
|
|
1
|
+
(function (tree) {
|
2
|
+
tree.joinSelectorVisitor = function() {
|
3
|
+
this.contexts = [[]];
|
4
|
+
this._visitor = new tree.visitor(this);
|
5
|
+
};
|
6
|
+
|
7
|
+
tree.joinSelectorVisitor.prototype = {
|
8
|
+
run: function (root) {
|
9
|
+
return this._visitor.visit(root);
|
10
|
+
},
|
11
|
+
visitRule: function (ruleNode, visitArgs) {
|
12
|
+
visitArgs.visitDeeper = false;
|
13
|
+
},
|
14
|
+
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
|
15
|
+
visitArgs.visitDeeper = false;
|
16
|
+
},
|
17
|
+
|
18
|
+
visitRuleset: function (rulesetNode, visitArgs) {
|
19
|
+
var context = this.contexts[this.contexts.length - 1];
|
20
|
+
var paths = [];
|
21
|
+
this.contexts.push(paths);
|
22
|
+
|
23
|
+
if (! rulesetNode.root) {
|
24
|
+
rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);
|
25
|
+
rulesetNode.paths = paths;
|
26
|
+
}
|
27
|
+
},
|
28
|
+
visitRulesetOut: function (rulesetNode) {
|
29
|
+
this.contexts.length = this.contexts.length - 1;
|
30
|
+
},
|
31
|
+
visitMedia: function (mediaNode, visitArgs) {
|
32
|
+
var context = this.contexts[this.contexts.length - 1];
|
33
|
+
mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia);
|
34
|
+
}
|
35
|
+
};
|
36
|
+
|
37
|
+
})(require('./tree'));
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// lessc_helper.js
|
2
2
|
//
|
3
3
|
// helper functions for lessc
|
4
|
-
sys = require('util');
|
4
|
+
var sys = require('util');
|
5
5
|
|
6
6
|
var lessc_helper = {
|
7
7
|
|
@@ -29,14 +29,18 @@ var lessc_helper = {
|
|
29
29
|
sys.puts("");
|
30
30
|
sys.puts("options:");
|
31
31
|
sys.puts(" -h, --help Print help (this message) and exit.");
|
32
|
-
sys.puts(" --include-path
|
32
|
+
sys.puts(" --include-path=PATHS Set include paths. Separated by `:'. Use `;' on Windows.");
|
33
|
+
sys.puts(" -M, --depends Output a makefile import dependency list to stdout");
|
33
34
|
sys.puts(" --no-color Disable colorized output.");
|
35
|
+
sys.puts(" --no-ie-compat Disable IE compatibility checks.");
|
36
|
+
sys.puts(" -l, --lint Syntax check only (lint).");
|
34
37
|
sys.puts(" -s, --silent Suppress output of error messages.");
|
35
38
|
sys.puts(" --strict-imports Force evaluation of imports.");
|
36
39
|
sys.puts(" --verbose Be verbose.");
|
37
40
|
sys.puts(" -v, --version Print version number and exit.");
|
38
41
|
sys.puts(" -x, --compress Compress output by removing some whitespaces.");
|
39
42
|
sys.puts(" --yui-compress Compress output using ycssmin");
|
43
|
+
sys.puts(" --max-line-len=LINELEN Max line length used by ycssmin");
|
40
44
|
sys.puts(" -O0, -O1, -O2 Set the parser's optimization level. The lower");
|
41
45
|
sys.puts(" the number, the less nodes it will create in the");
|
42
46
|
sys.puts(" tree. This could matter for debugging, or if you");
|
@@ -47,9 +51,14 @@ var lessc_helper = {
|
|
47
51
|
sys.puts(" that will output the information within a fake");
|
48
52
|
sys.puts(" media query which is compatible with the SASS");
|
49
53
|
sys.puts(" format, and 'all' which will do both.");
|
50
|
-
sys.puts(" -rp, --rootpath
|
51
|
-
sys.puts(" Works with or
|
54
|
+
sys.puts(" -rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls.");
|
55
|
+
sys.puts(" Works with or without the relative-urls option.");
|
52
56
|
sys.puts(" -ru, --relative-urls re-write relative urls to the base less file.");
|
57
|
+
sys.puts(" -sm=on|off Turn on or off strict math, where in strict mode, math");
|
58
|
+
sys.puts(" --strict-math=on|off requires brackets. This option may default to on and then");
|
59
|
+
sys.puts(" be removed in the future.");
|
60
|
+
sys.puts(" -su=on|off Allow mixed units, e.g. 1px+1em or 1px*1px which have units");
|
61
|
+
sys.puts(" --strict-units=on|off that cannot be represented.");
|
53
62
|
sys.puts("");
|
54
63
|
sys.puts("Report bugs to: http://github.com/cloudhead/less.js/issues");
|
55
64
|
sys.puts("Home page: <http://lesscss.org/>");
|
@@ -66,16 +66,10 @@ less.Parser = function Parser(env) {
|
|
66
66
|
var that = this;
|
67
67
|
|
68
68
|
// Top parser on an import tree must be sure there is one "env"
|
69
|
-
// which will then be passed
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided
|
74
|
-
if (!env.files) { env.files = {}; }
|
75
|
-
|
76
|
-
// This function is called after all files
|
77
|
-
// have been imported through `@import`.
|
78
|
-
var finish = function () {};
|
69
|
+
// which will then be passed around by reference.
|
70
|
+
if (!(env instanceof tree.parseEnv)) {
|
71
|
+
env = new tree.parseEnv(env);
|
72
|
+
}
|
79
73
|
|
80
74
|
var imports = this.imports = {
|
81
75
|
paths: env.paths || [], // Search paths, when importing
|
@@ -84,31 +78,29 @@ less.Parser = function Parser(env) {
|
|
84
78
|
contents: env.contents, // Holds the imported file contents
|
85
79
|
mime: env.mime, // MIME type of .less files
|
86
80
|
error: null, // Error in parsing/evaluating an import
|
87
|
-
push: function (path, callback) {
|
88
|
-
var
|
81
|
+
push: function (path, currentFileInfo, callback) {
|
82
|
+
var parserImporter = this;
|
89
83
|
this.queue.push(path);
|
90
84
|
|
91
85
|
//
|
92
86
|
// Import a file asynchronously
|
93
87
|
//
|
94
|
-
less.Parser.importer(path,
|
95
|
-
|
96
|
-
|
97
|
-
var imported = fullPath in that.files;
|
88
|
+
less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) {
|
89
|
+
parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue
|
98
90
|
|
99
|
-
|
91
|
+
var imported = fullPath in parserImporter.files;
|
100
92
|
|
101
|
-
|
93
|
+
parserImporter.files[fullPath] = root; // Store the root
|
102
94
|
|
95
|
+
if (e && !parserImporter.error) { parserImporter.error = e; }
|
96
|
+
|
103
97
|
callback(e, root, imported);
|
104
|
-
|
105
|
-
if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing
|
106
98
|
}, env);
|
107
99
|
}
|
108
100
|
};
|
109
101
|
|
110
|
-
function save() { temp = chunks[j], memo = i, current = i }
|
111
|
-
function restore() { chunks[j] = temp, i = memo, current = i }
|
102
|
+
function save() { temp = chunks[j], memo = i, current = i; }
|
103
|
+
function restore() { chunks[j] = temp, i = memo, current = i; }
|
112
104
|
|
113
105
|
function sync() {
|
114
106
|
if (i > current) {
|
@@ -217,7 +209,7 @@ less.Parser = function Parser(env) {
|
|
217
209
|
}
|
218
210
|
|
219
211
|
function getInput(e, env) {
|
220
|
-
if (e.filename && env.filename && (e.filename !== env.filename)) {
|
212
|
+
if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
|
221
213
|
return parser.imports.contents[e.filename];
|
222
214
|
} else {
|
223
215
|
return input;
|
@@ -233,17 +225,15 @@ less.Parser = function Parser(env) {
|
|
233
225
|
column: column };
|
234
226
|
}
|
235
227
|
|
236
|
-
function
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
}
|
228
|
+
function getDebugInfo(index, inputStream, env) {
|
229
|
+
var filename = env.currentFileInfo.filename;
|
230
|
+
if(less.mode !== 'browser' && less.mode !== 'rhino') {
|
231
|
+
filename = require('path').resolve(filename);
|
232
|
+
}
|
242
233
|
|
243
|
-
function getDebugInfo(index, inputStream, e) {
|
244
234
|
return {
|
245
235
|
lineNumber: getLocation(index, inputStream).line + 1,
|
246
|
-
fileName:
|
236
|
+
fileName: filename
|
247
237
|
};
|
248
238
|
}
|
249
239
|
|
@@ -256,7 +246,7 @@ less.Parser = function Parser(env) {
|
|
256
246
|
|
257
247
|
this.type = e.type || 'Syntax';
|
258
248
|
this.message = e.message;
|
259
|
-
this.filename = e.filename || env.filename;
|
249
|
+
this.filename = e.filename || env.currentFileInfo.filename;
|
260
250
|
this.index = e.index;
|
261
251
|
this.line = typeof(line) === 'number' ? line + 1 : null;
|
262
252
|
this.callLine = e.call && (getLocation(e.call, input).line + 1);
|
@@ -270,6 +260,9 @@ less.Parser = function Parser(env) {
|
|
270
260
|
];
|
271
261
|
}
|
272
262
|
|
263
|
+
LessError.prototype = new Error();
|
264
|
+
LessError.prototype.constructor = LessError;
|
265
|
+
|
273
266
|
this.env = env = env || {};
|
274
267
|
|
275
268
|
// The optimization level dictates the thoroughness of the parser,
|
@@ -278,8 +271,6 @@ less.Parser = function Parser(env) {
|
|
278
271
|
// the individual nodes in the tree.
|
279
272
|
this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
|
280
273
|
|
281
|
-
this.env.filename = this.env.filename || null;
|
282
|
-
|
283
274
|
//
|
284
275
|
// The Parser
|
285
276
|
//
|
@@ -357,7 +348,7 @@ less.Parser = function Parser(env) {
|
|
357
348
|
index: i-1,
|
358
349
|
type: 'Parse',
|
359
350
|
message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
|
360
|
-
filename: env.filename
|
351
|
+
filename: env.currentFileInfo.filename
|
361
352
|
}, env);
|
362
353
|
}
|
363
354
|
|
@@ -365,7 +356,7 @@ less.Parser = function Parser(env) {
|
|
365
356
|
})([[]]);
|
366
357
|
|
367
358
|
if (error) {
|
368
|
-
return callback(error, env);
|
359
|
+
return callback(new(LessError)(error, env));
|
369
360
|
}
|
370
361
|
|
371
362
|
// Start with the primary rule.
|
@@ -375,6 +366,7 @@ less.Parser = function Parser(env) {
|
|
375
366
|
try {
|
376
367
|
root = new(tree.Ruleset)([], $(this.parsers.primary));
|
377
368
|
root.root = true;
|
369
|
+
root.firstRoot = true;
|
378
370
|
} catch (e) {
|
379
371
|
return callback(new(LessError)(e, env));
|
380
372
|
}
|
@@ -383,9 +375,10 @@ less.Parser = function Parser(env) {
|
|
383
375
|
var line, lines, column;
|
384
376
|
|
385
377
|
return function (options, variables) {
|
386
|
-
var frames = [], importError;
|
387
|
-
|
388
378
|
options = options || {};
|
379
|
+
var importError,
|
380
|
+
evalEnv = new tree.evalEnv(options);
|
381
|
+
|
389
382
|
//
|
390
383
|
// Allows setting variables with a hash, so:
|
391
384
|
//
|
@@ -411,23 +404,28 @@ less.Parser = function Parser(env) {
|
|
411
404
|
}
|
412
405
|
return new(tree.Rule)('@' + k, value, false, 0);
|
413
406
|
});
|
414
|
-
frames = [new(tree.Ruleset)(null, variables)];
|
407
|
+
evalEnv.frames = [new(tree.Ruleset)(null, variables)];
|
415
408
|
}
|
416
409
|
|
417
410
|
try {
|
418
|
-
var
|
419
|
-
|
411
|
+
var evaldRoot = evaluate.call(this, evalEnv);
|
412
|
+
|
413
|
+
new(tree.joinSelectorVisitor)()
|
414
|
+
.run(evaldRoot);
|
415
|
+
|
416
|
+
new(tree.processExtendsVisitor)()
|
417
|
+
.run(evaldRoot);
|
418
|
+
|
419
|
+
var css = evaldRoot.toCSS({
|
420
|
+
compress: Boolean(options.compress),
|
421
|
+
dumpLineNumbers: env.dumpLineNumbers,
|
422
|
+
strictUnits: Boolean(options.strictUnits)});
|
420
423
|
} catch (e) {
|
421
424
|
throw new(LessError)(e, env);
|
422
425
|
}
|
423
426
|
|
424
|
-
if ((importError = parser.imports.error)) { // Check if there was an error during importing
|
425
|
-
if (importError instanceof LessError) throw importError;
|
426
|
-
else throw new(LessError)(importError, env);
|
427
|
-
}
|
428
|
-
|
429
427
|
if (options.yuicompress && less.mode === 'node') {
|
430
|
-
return require('ycssmin').cssmin(css);
|
428
|
+
return require('ycssmin').cssmin(css, options.maxLineLen);
|
431
429
|
} else if (options.compress) {
|
432
430
|
return css.replace(/(\s)+/g, "$1");
|
433
431
|
} else {
|
@@ -453,9 +451,9 @@ less.Parser = function Parser(env) {
|
|
453
451
|
|
454
452
|
error = {
|
455
453
|
type: "Parse",
|
456
|
-
message: "
|
454
|
+
message: "Unrecognised input",
|
457
455
|
index: i,
|
458
|
-
filename: env.filename,
|
456
|
+
filename: env.currentFileInfo.filename,
|
459
457
|
line: line,
|
460
458
|
column: column,
|
461
459
|
extract: [
|
@@ -466,14 +464,26 @@ less.Parser = function Parser(env) {
|
|
466
464
|
};
|
467
465
|
}
|
468
466
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
467
|
+
var finish = function (e) {
|
468
|
+
e = error || e || parser.imports.error;
|
469
|
+
|
470
|
+
if (e) {
|
471
|
+
if (!(e instanceof LessError)) {
|
472
|
+
e = new(LessError)(e, env);
|
473
|
+
}
|
474
|
+
|
475
|
+
callback(e);
|
476
|
+
}
|
477
|
+
else {
|
478
|
+
callback(null, root);
|
479
|
+
}
|
480
|
+
};
|
481
|
+
|
482
|
+
if (env.processImports !== false) {
|
483
|
+
new tree.importVisitor(this.imports, finish)
|
484
|
+
.run(root);
|
475
485
|
} else {
|
476
|
-
|
486
|
+
finish();
|
477
487
|
}
|
478
488
|
},
|
479
489
|
|
@@ -525,7 +535,7 @@ less.Parser = function Parser(env) {
|
|
525
535
|
primary: function () {
|
526
536
|
var node, root = [];
|
527
537
|
|
528
|
-
while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
|
538
|
+
while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
|
529
539
|
$(this.mixin.call) || $(this.comment) || $(this.directive))
|
530
540
|
|| $(/^[\s\n]+/) || $(/^;+/)) {
|
531
541
|
node && root.push(node);
|
@@ -558,7 +568,7 @@ less.Parser = function Parser(env) {
|
|
558
568
|
// "milky way" 'he\'s the one!'
|
559
569
|
//
|
560
570
|
quoted: function () {
|
561
|
-
var str, j = i, e;
|
571
|
+
var str, j = i, e, index = i;
|
562
572
|
|
563
573
|
if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
|
564
574
|
if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
|
@@ -566,7 +576,7 @@ less.Parser = function Parser(env) {
|
|
566
576
|
e && $('~');
|
567
577
|
|
568
578
|
if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
|
569
|
-
return new(tree.Quoted)(str[0], str[1] || str[2], e);
|
579
|
+
return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
|
570
580
|
}
|
571
581
|
},
|
572
582
|
|
@@ -607,7 +617,7 @@ less.Parser = function Parser(env) {
|
|
607
617
|
nameLC = name.toLowerCase();
|
608
618
|
|
609
619
|
if (nameLC === 'url') { return null }
|
610
|
-
else
|
620
|
+
else { i += name.length }
|
611
621
|
|
612
622
|
if (nameLC === 'alpha') {
|
613
623
|
alpha_ret = $(this.alpha);
|
@@ -620,9 +630,11 @@ less.Parser = function Parser(env) {
|
|
620
630
|
|
621
631
|
args = $(this.entities.arguments);
|
622
632
|
|
623
|
-
if (! $(')'))
|
633
|
+
if (! $(')')) {
|
634
|
+
return;
|
635
|
+
}
|
624
636
|
|
625
|
-
if (name) { return new(tree.Call)(name, args, index, env.
|
637
|
+
if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); }
|
626
638
|
},
|
627
639
|
arguments: function () {
|
628
640
|
var args = [], arg;
|
@@ -634,8 +646,7 @@ less.Parser = function Parser(env) {
|
|
634
646
|
return args;
|
635
647
|
},
|
636
648
|
literal: function () {
|
637
|
-
return $(this.entities.
|
638
|
-
$(this.entities.dimension) ||
|
649
|
+
return $(this.entities.dimension) ||
|
639
650
|
$(this.entities.color) ||
|
640
651
|
$(this.entities.quoted) ||
|
641
652
|
$(this.entities.unicodeDescriptor);
|
@@ -671,7 +682,7 @@ less.Parser = function Parser(env) {
|
|
671
682
|
expect(')');
|
672
683
|
|
673
684
|
return new(tree.URL)((value.value != null || value instanceof tree.Variable)
|
674
|
-
? value : new(tree.Anonymous)(value), env.
|
685
|
+
? value : new(tree.Anonymous)(value), env.currentFileInfo);
|
675
686
|
},
|
676
687
|
|
677
688
|
//
|
@@ -686,7 +697,7 @@ less.Parser = function Parser(env) {
|
|
686
697
|
var name, index = i;
|
687
698
|
|
688
699
|
if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
|
689
|
-
return new(tree.Variable)(name, index, env.
|
700
|
+
return new(tree.Variable)(name, index, env.currentFileInfo);
|
690
701
|
}
|
691
702
|
},
|
692
703
|
|
@@ -695,7 +706,7 @@ less.Parser = function Parser(env) {
|
|
695
706
|
var name, curly, index = i;
|
696
707
|
|
697
708
|
if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
|
698
|
-
return new(tree.Variable)("@" + curly[1], index, env.
|
709
|
+
return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo);
|
699
710
|
}
|
700
711
|
},
|
701
712
|
|
@@ -724,25 +735,11 @@ less.Parser = function Parser(env) {
|
|
724
735
|
//Is the first char of the dimension 0-9, '.', '+' or '-'
|
725
736
|
if ((c > 57 || c < 43) || c === 47 || c == 44) return;
|
726
737
|
|
727
|
-
if (value = $(/^([+-]?\d*\.?\d+)(
|
738
|
+
if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {
|
728
739
|
return new(tree.Dimension)(value[1], value[2]);
|
729
740
|
}
|
730
741
|
},
|
731
742
|
|
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
743
|
//
|
747
744
|
// A unicode descriptor, as is used in unicode-range
|
748
745
|
//
|
@@ -787,26 +784,46 @@ less.Parser = function Parser(env) {
|
|
787
784
|
},
|
788
785
|
|
789
786
|
//
|
790
|
-
//
|
791
|
-
//
|
792
|
-
// small/12px
|
793
|
-
//
|
794
|
-
// We need to peek first, or we'll match on keywords and dimensions
|
787
|
+
// extend syntax - used to extend selectors
|
795
788
|
//
|
796
|
-
|
797
|
-
var
|
789
|
+
extend: function(isRule) {
|
790
|
+
var elements, e, index = i, option, extendList = [];
|
798
791
|
|
799
|
-
if (
|
792
|
+
if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; }
|
800
793
|
|
801
|
-
|
794
|
+
do {
|
795
|
+
option = null;
|
796
|
+
elements = [];
|
797
|
+
while (true) {
|
798
|
+
option = $(/^(all)(?=\s*(\)|,))/);
|
799
|
+
if (option) { break; }
|
800
|
+
e = $(this.element);
|
801
|
+
if (!e) { break; }
|
802
|
+
elements.push(e);
|
803
|
+
}
|
804
|
+
|
805
|
+
option = option && option[1];
|
806
|
+
|
807
|
+
extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index));
|
808
|
+
|
809
|
+
} while($(","))
|
810
|
+
|
811
|
+
expect(/^\)/);
|
802
812
|
|
803
|
-
if (
|
804
|
-
|
813
|
+
if (isRule) {
|
814
|
+
expect(/^;/);
|
805
815
|
}
|
806
816
|
|
807
|
-
|
817
|
+
return extendList;
|
808
818
|
},
|
809
819
|
|
820
|
+
//
|
821
|
+
// extendRule - used in a rule to extend all the parent selectors
|
822
|
+
//
|
823
|
+
extendRule: function() {
|
824
|
+
return this.extend(true);
|
825
|
+
},
|
826
|
+
|
810
827
|
//
|
811
828
|
// Mixins
|
812
829
|
//
|
@@ -823,10 +840,10 @@ less.Parser = function Parser(env) {
|
|
823
840
|
// selector for now.
|
824
841
|
//
|
825
842
|
call: function () {
|
826
|
-
var elements = [], e, c,
|
843
|
+
var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false;
|
827
844
|
|
828
845
|
if (s !== '.' && s !== '#') { return }
|
829
|
-
|
846
|
+
|
830
847
|
save(); // stop us absorbing part of an invalid selector
|
831
848
|
|
832
849
|
while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
|
@@ -834,71 +851,119 @@ less.Parser = function Parser(env) {
|
|
834
851
|
c = $('>');
|
835
852
|
}
|
836
853
|
if ($('(')) {
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
854
|
+
args = this.mixin.args.call(this, true).args;
|
855
|
+
expect(')');
|
856
|
+
}
|
857
|
+
|
858
|
+
args = args || [];
|
841
859
|
|
860
|
+
if ($(this.important)) {
|
861
|
+
important = true;
|
862
|
+
}
|
863
|
+
|
864
|
+
if (elements.length > 0 && ($(';') || peek('}'))) {
|
865
|
+
return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
|
866
|
+
}
|
867
|
+
|
868
|
+
restore();
|
869
|
+
},
|
870
|
+
args: function (isCall) {
|
871
|
+
var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg,
|
872
|
+
returner = {args:null, variadic: false};
|
873
|
+
while (true) {
|
874
|
+
if (isCall) {
|
875
|
+
arg = $(this.expression);
|
876
|
+
} else {
|
877
|
+
$(this.comment);
|
878
|
+
if (input.charAt(i) === '.' && $(/^\.{3}/)) {
|
879
|
+
returner.variadic = true;
|
880
|
+
if ($(";") && !isSemiColonSeperated) {
|
881
|
+
isSemiColonSeperated = true;
|
882
|
+
}
|
883
|
+
(isSemiColonSeperated ? argsSemiColon : argsComma)
|
884
|
+
.push({ variadic: true });
|
885
|
+
break;
|
886
|
+
}
|
887
|
+
arg = $(this.entities.variable) || $(this.entities.literal)
|
888
|
+
|| $(this.entities.keyword);
|
889
|
+
}
|
890
|
+
|
891
|
+
if (!arg) {
|
892
|
+
break;
|
893
|
+
}
|
894
|
+
|
895
|
+
nameLoop = null;
|
896
|
+
if (arg.throwAwayComments) {
|
897
|
+
arg.throwAwayComments();
|
898
|
+
}
|
899
|
+
value = arg;
|
900
|
+
var val = null;
|
901
|
+
|
902
|
+
if (isCall) {
|
842
903
|
// Variable
|
843
904
|
if (arg.value.length == 1) {
|
844
905
|
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
906
|
}
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
907
|
+
} else {
|
908
|
+
val = arg;
|
909
|
+
}
|
910
|
+
|
911
|
+
if (val && val instanceof tree.Variable) {
|
912
|
+
if ($(':')) {
|
913
|
+
if (expressions.length > 0) {
|
914
|
+
if (isSemiColonSeperated) {
|
915
|
+
error("Cannot mix ; and , as delimiter types");
|
916
|
+
}
|
917
|
+
expressionContainsNamed = true;
|
871
918
|
}
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
919
|
+
value = expect(this.expression);
|
920
|
+
nameLoop = (name = val.name);
|
921
|
+
} else if (!isCall && $(/^\.{3}/)) {
|
922
|
+
returner.variadic = true;
|
923
|
+
if ($(";") && !isSemiColonSeperated) {
|
924
|
+
isSemiColonSeperated = true;
|
877
925
|
}
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
926
|
+
(isSemiColonSeperated ? argsSemiColon : argsComma)
|
927
|
+
.push({ name: arg.name, variadic: true });
|
928
|
+
break;
|
929
|
+
} else if (!isCall) {
|
930
|
+
name = nameLoop = val.name;
|
931
|
+
value = null;
|
883
932
|
}
|
884
933
|
}
|
885
934
|
|
886
|
-
|
887
|
-
|
935
|
+
if (value) {
|
936
|
+
expressions.push(value);
|
937
|
+
}
|
888
938
|
|
889
|
-
|
939
|
+
argsComma.push({ name:nameLoop, value:value });
|
890
940
|
|
891
|
-
|
892
|
-
|
893
|
-
|
941
|
+
if ($(',')) {
|
942
|
+
continue;
|
943
|
+
}
|
894
944
|
|
895
|
-
|
896
|
-
|
945
|
+
if ($(';') || isSemiColonSeperated) {
|
946
|
+
|
947
|
+
if (expressionContainsNamed) {
|
948
|
+
error("Cannot mix ; and , as delimiter types");
|
949
|
+
}
|
950
|
+
|
951
|
+
isSemiColonSeperated = true;
|
952
|
+
|
953
|
+
if (expressions.length > 1) {
|
954
|
+
value = new (tree.Value)(expressions);
|
955
|
+
}
|
956
|
+
argsSemiColon.push({ name:name, value:value });
|
957
|
+
|
958
|
+
name = null;
|
959
|
+
expressions = [];
|
960
|
+
expressionContainsNamed = false;
|
961
|
+
}
|
897
962
|
}
|
898
|
-
|
899
|
-
restore();
|
900
|
-
},
|
901
963
|
|
964
|
+
returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
|
965
|
+
return returner;
|
966
|
+
},
|
902
967
|
//
|
903
968
|
// A Mixin definition, with a list of parameters
|
904
969
|
//
|
@@ -928,35 +993,11 @@ less.Parser = function Parser(env) {
|
|
928
993
|
if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
|
929
994
|
name = match[1];
|
930
995
|
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
variadic = true;
|
935
|
-
params.push({ variadic: true });
|
936
|
-
break;
|
937
|
-
} else if (param = $(this.entities.variable) || $(this.entities.literal)
|
938
|
-
|| $(this.entities.keyword)) {
|
939
|
-
// Variable
|
940
|
-
if (param instanceof tree.Variable) {
|
941
|
-
if ($(':')) {
|
942
|
-
value = expect(this.expression, 'expected expression');
|
943
|
-
params.push({ name: param.name, value: value });
|
944
|
-
} else if ($(/^\.{3}/)) {
|
945
|
-
params.push({ name: param.name, variadic: true });
|
946
|
-
variadic = true;
|
947
|
-
break;
|
948
|
-
} else {
|
949
|
-
params.push({ name: param.name });
|
950
|
-
}
|
951
|
-
} else {
|
952
|
-
params.push({ value: param });
|
953
|
-
}
|
954
|
-
} else {
|
955
|
-
break;
|
956
|
-
}
|
957
|
-
} while ($(',') || $(';'))
|
996
|
+
var argInfo = this.mixin.args.call(this, false);
|
997
|
+
params = argInfo.args;
|
998
|
+
variadic = argInfo.variadic;
|
958
999
|
|
959
|
-
// .mixincall("@{a}");
|
1000
|
+
// .mixincall("@{a}");
|
960
1001
|
// looks a bit like a mixin definition.. so we have to be nice and restore
|
961
1002
|
if (!$(')')) {
|
962
1003
|
furthest = i;
|
@@ -1036,9 +1077,7 @@ less.Parser = function Parser(env) {
|
|
1036
1077
|
|
1037
1078
|
if (! e) {
|
1038
1079
|
if ($('(')) {
|
1039
|
-
if ((v = ($(this.
|
1040
|
-
$(this.entities.variable) ||
|
1041
|
-
$(this.selector))) &&
|
1080
|
+
if ((v = ($(this.selector))) &&
|
1042
1081
|
$(')')) {
|
1043
1082
|
e = new(tree.Paren)(v);
|
1044
1083
|
}
|
@@ -1058,7 +1097,7 @@ less.Parser = function Parser(env) {
|
|
1058
1097
|
// we deal with this in *combinator.js*.
|
1059
1098
|
//
|
1060
1099
|
combinator: function () {
|
1061
|
-
var
|
1100
|
+
var c = input.charAt(i);
|
1062
1101
|
|
1063
1102
|
if (c === '>' || c === '+' || c === '~' || c === '|') {
|
1064
1103
|
i++;
|
@@ -1080,38 +1119,41 @@ less.Parser = function Parser(env) {
|
|
1080
1119
|
// Selectors are made out of one or more Elements, see above.
|
1081
1120
|
//
|
1082
1121
|
selector: function () {
|
1083
|
-
var sel, e, elements = [], c,
|
1122
|
+
var sel, e, elements = [], c, extend, extendList = [];
|
1084
1123
|
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1124
|
+
while ((extend = $(this.extend)) || (e = $(this.element))) {
|
1125
|
+
if (extend) {
|
1126
|
+
extendList.push.apply(extendList, extend);
|
1127
|
+
} else {
|
1128
|
+
if (extendList.length) {
|
1129
|
+
error("Extend can only be used at the end of selector");
|
1130
|
+
}
|
1131
|
+
c = input.charAt(i);
|
1132
|
+
elements.push(e)
|
1133
|
+
e = null;
|
1134
|
+
}
|
1095
1135
|
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
|
1096
1136
|
}
|
1097
1137
|
|
1098
|
-
if (elements.length > 0) { return new(tree.Selector)(elements) }
|
1138
|
+
if (elements.length > 0) { return new(tree.Selector)(elements, extendList); }
|
1139
|
+
if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
|
1099
1140
|
},
|
1100
1141
|
attribute: function () {
|
1101
1142
|
var attr = '', key, val, op;
|
1102
1143
|
|
1103
1144
|
if (! $('[')) return;
|
1104
1145
|
|
1105
|
-
if (key = $(
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1146
|
+
if (!(key = $(this.entities.variableCurly))) {
|
1147
|
+
key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
if ((op = $(/^[|~*$^]?=/))) {
|
1151
|
+
val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly);
|
1110
1152
|
}
|
1111
1153
|
|
1112
|
-
|
1154
|
+
expect(']');
|
1113
1155
|
|
1114
|
-
|
1156
|
+
return new(tree.Attribute)(key, op, val);
|
1115
1157
|
},
|
1116
1158
|
|
1117
1159
|
//
|
@@ -1129,7 +1171,7 @@ less.Parser = function Parser(env) {
|
|
1129
1171
|
// div, .class, body > p {...}
|
1130
1172
|
//
|
1131
1173
|
ruleset: function () {
|
1132
|
-
var selectors = [], s, rules,
|
1174
|
+
var selectors = [], s, rules, debugInfo;
|
1133
1175
|
|
1134
1176
|
save();
|
1135
1177
|
|
@@ -1154,31 +1196,39 @@ less.Parser = function Parser(env) {
|
|
1154
1196
|
restore();
|
1155
1197
|
}
|
1156
1198
|
},
|
1157
|
-
rule: function () {
|
1158
|
-
var name, value, c = input.charAt(i), important
|
1199
|
+
rule: function (tryAnonymous) {
|
1200
|
+
var name, value, c = input.charAt(i), important;
|
1159
1201
|
save();
|
1160
1202
|
|
1161
1203
|
if (c === '.' || c === '#' || c === '&') { return }
|
1162
1204
|
|
1163
1205
|
if (name = $(this.variable) || $(this.property)) {
|
1164
|
-
if
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
value = $(this.value);
|
1171
|
-
}
|
1206
|
+
// prefer to try to parse first if its a variable or we are compressing
|
1207
|
+
// but always fallback on the other one
|
1208
|
+
value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
|
1209
|
+
($(this.value) || $(this.anonymousValue)) :
|
1210
|
+
($(this.anonymousValue) || $(this.value));
|
1211
|
+
|
1172
1212
|
important = $(this.important);
|
1173
1213
|
|
1174
1214
|
if (value && $(this.end)) {
|
1175
|
-
return new(tree.Rule)(name, value, important, memo);
|
1215
|
+
return new(tree.Rule)(name, value, important, memo, env.currentFileInfo);
|
1176
1216
|
} else {
|
1177
1217
|
furthest = i;
|
1178
1218
|
restore();
|
1219
|
+
if (value && !tryAnonymous) {
|
1220
|
+
return this.rule(true);
|
1221
|
+
}
|
1179
1222
|
}
|
1180
1223
|
}
|
1181
1224
|
},
|
1225
|
+
anonymousValue: function () {
|
1226
|
+
var match;
|
1227
|
+
if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) {
|
1228
|
+
i += match[0].length - 1;
|
1229
|
+
return new(tree.Anonymous)(match[1]);
|
1230
|
+
}
|
1231
|
+
},
|
1182
1232
|
|
1183
1233
|
//
|
1184
1234
|
// An @import directive
|
@@ -1192,21 +1242,58 @@ less.Parser = function Parser(env) {
|
|
1192
1242
|
//
|
1193
1243
|
"import": function () {
|
1194
1244
|
var path, features, index = i;
|
1195
|
-
|
1245
|
+
|
1196
1246
|
save();
|
1197
|
-
|
1198
|
-
var dir = $(/^@import
|
1247
|
+
|
1248
|
+
var dir = $(/^@import?\s+/);
|
1249
|
+
|
1250
|
+
var options = (dir ? $(this.importOptions) : null) || {};
|
1199
1251
|
|
1200
1252
|
if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
|
1201
1253
|
features = $(this.mediaFeatures);
|
1202
1254
|
if ($(';')) {
|
1203
|
-
|
1255
|
+
features = features && new(tree.Value)(features);
|
1256
|
+
return new(tree.Import)(path, features, options, index, env.currentFileInfo);
|
1204
1257
|
}
|
1205
1258
|
}
|
1206
|
-
|
1259
|
+
|
1207
1260
|
restore();
|
1208
1261
|
},
|
1209
1262
|
|
1263
|
+
importOptions: function() {
|
1264
|
+
var o, options = {}, optionName, value;
|
1265
|
+
|
1266
|
+
// list of options, surrounded by parens
|
1267
|
+
if (! $('(')) { return null; }
|
1268
|
+
do {
|
1269
|
+
if (o = $(this.importOption)) {
|
1270
|
+
optionName = o;
|
1271
|
+
value = true;
|
1272
|
+
switch(optionName) {
|
1273
|
+
case "css":
|
1274
|
+
optionName = "less";
|
1275
|
+
value = false;
|
1276
|
+
break;
|
1277
|
+
case "once":
|
1278
|
+
optionName = "multiple";
|
1279
|
+
value = false;
|
1280
|
+
break;
|
1281
|
+
}
|
1282
|
+
options[optionName] = value;
|
1283
|
+
if (! $(',')) { break }
|
1284
|
+
}
|
1285
|
+
} while (o);
|
1286
|
+
expect(')');
|
1287
|
+
return options;
|
1288
|
+
},
|
1289
|
+
|
1290
|
+
importOption: function() {
|
1291
|
+
var opt = $(/^(less|css|multiple|once)/);
|
1292
|
+
if (opt) {
|
1293
|
+
return opt[1];
|
1294
|
+
}
|
1295
|
+
},
|
1296
|
+
|
1210
1297
|
mediaFeature: function () {
|
1211
1298
|
var e, p, nodes = [];
|
1212
1299
|
|
@@ -1215,10 +1302,10 @@ less.Parser = function Parser(env) {
|
|
1215
1302
|
nodes.push(e);
|
1216
1303
|
} else if ($('(')) {
|
1217
1304
|
p = $(this.property);
|
1218
|
-
e = $(this.
|
1305
|
+
e = $(this.value);
|
1219
1306
|
if ($(')')) {
|
1220
1307
|
if (p && e) {
|
1221
|
-
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
|
1308
|
+
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
|
1222
1309
|
} else if (e) {
|
1223
1310
|
nodes.push(new(tree.Paren)(e));
|
1224
1311
|
} else {
|
@@ -1281,7 +1368,7 @@ less.Parser = function Parser(env) {
|
|
1281
1368
|
if (value = $(this['import']) || $(this.media)) {
|
1282
1369
|
return value;
|
1283
1370
|
}
|
1284
|
-
|
1371
|
+
|
1285
1372
|
save();
|
1286
1373
|
|
1287
1374
|
name = $(/^@[a-z-]+/);
|
@@ -1346,24 +1433,8 @@ less.Parser = function Parser(env) {
|
|
1346
1433
|
return directive;
|
1347
1434
|
}
|
1348
1435
|
}
|
1349
|
-
|
1350
|
-
restore();
|
1351
|
-
},
|
1352
|
-
font: function () {
|
1353
|
-
var value = [], expression = [], weight, shorthand, font, e;
|
1354
1436
|
|
1355
|
-
|
1356
|
-
expression.push(e);
|
1357
|
-
}
|
1358
|
-
value.push(new(tree.Expression)(expression));
|
1359
|
-
|
1360
|
-
if ($(',')) {
|
1361
|
-
while (e = $(this.expression)) {
|
1362
|
-
value.push(e);
|
1363
|
-
if (! $(',')) { break }
|
1364
|
-
}
|
1365
|
-
}
|
1366
|
-
return new(tree.Value)(value);
|
1437
|
+
restore();
|
1367
1438
|
},
|
1368
1439
|
|
1369
1440
|
//
|
@@ -1392,27 +1463,44 @@ less.Parser = function Parser(env) {
|
|
1392
1463
|
}
|
1393
1464
|
},
|
1394
1465
|
sub: function () {
|
1395
|
-
var e;
|
1466
|
+
var a, e;
|
1396
1467
|
|
1397
|
-
if ($('(')
|
1398
|
-
|
1468
|
+
if ($('(')) {
|
1469
|
+
if (a = $(this.addition)) {
|
1470
|
+
e = new(tree.Expression)([a]);
|
1471
|
+
expect(')');
|
1472
|
+
e.parens = true;
|
1473
|
+
return e;
|
1474
|
+
}
|
1399
1475
|
}
|
1400
1476
|
},
|
1401
1477
|
multiplication: function () {
|
1402
|
-
var m, a, op, operation;
|
1478
|
+
var m, a, op, operation, isSpaced, expression = [];
|
1403
1479
|
if (m = $(this.operand)) {
|
1404
|
-
|
1405
|
-
|
1480
|
+
isSpaced = isWhitespace(input.charAt(i - 1));
|
1481
|
+
while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) {
|
1482
|
+
if (a = $(this.operand)) {
|
1483
|
+
m.parensInOp = true;
|
1484
|
+
a.parensInOp = true;
|
1485
|
+
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
1486
|
+
isSpaced = isWhitespace(input.charAt(i - 1));
|
1487
|
+
} else {
|
1488
|
+
break;
|
1489
|
+
}
|
1406
1490
|
}
|
1407
1491
|
return operation || m;
|
1408
1492
|
}
|
1409
1493
|
},
|
1410
1494
|
addition: function () {
|
1411
|
-
var m, a, op, operation;
|
1495
|
+
var m, a, op, operation, isSpaced;
|
1412
1496
|
if (m = $(this.multiplication)) {
|
1413
|
-
|
1497
|
+
isSpaced = isWhitespace(input.charAt(i - 1));
|
1498
|
+
while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) &&
|
1414
1499
|
(a = $(this.multiplication))) {
|
1415
|
-
|
1500
|
+
m.parensInOp = true;
|
1501
|
+
a.parensInOp = true;
|
1502
|
+
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
1503
|
+
isSpaced = isWhitespace(input.charAt(i - 1));
|
1416
1504
|
}
|
1417
1505
|
return operation || m;
|
1418
1506
|
}
|
@@ -1458,8 +1546,13 @@ less.Parser = function Parser(env) {
|
|
1458
1546
|
var o = $(this.sub) || $(this.entities.dimension) ||
|
1459
1547
|
$(this.entities.color) || $(this.entities.variable) ||
|
1460
1548
|
$(this.entities.call);
|
1461
|
-
|
1462
|
-
|
1549
|
+
|
1550
|
+
if (negate) {
|
1551
|
+
o.parensInOp = true;
|
1552
|
+
o = new(tree.Negative)(o);
|
1553
|
+
}
|
1554
|
+
|
1555
|
+
return o;
|
1463
1556
|
},
|
1464
1557
|
|
1465
1558
|
//
|
@@ -1474,6 +1567,10 @@ less.Parser = function Parser(env) {
|
|
1474
1567
|
|
1475
1568
|
while (e = $(this.addition) || $(this.entity)) {
|
1476
1569
|
entities.push(e);
|
1570
|
+
// operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
|
1571
|
+
if (!peek(/^\/[\/*]/) && (delim = $('/'))) {
|
1572
|
+
entities.push(new(tree.Anonymous)(delim));
|
1573
|
+
}
|
1477
1574
|
}
|
1478
1575
|
if (entities.length > 0) {
|
1479
1576
|
return new(tree.Expression)(entities);
|
@@ -1482,7 +1579,7 @@ less.Parser = function Parser(env) {
|
|
1482
1579
|
property: function () {
|
1483
1580
|
var name;
|
1484
1581
|
|
1485
|
-
if (name = $(/^(\*?-?[_a-
|
1582
|
+
if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) {
|
1486
1583
|
return name[1];
|
1487
1584
|
}
|
1488
1585
|
}
|
@@ -1494,29 +1591,21 @@ if (less.mode === 'browser' || less.mode === 'rhino') {
|
|
1494
1591
|
//
|
1495
1592
|
// Used by `@import` directives
|
1496
1593
|
//
|
1497
|
-
less.Parser.importer = function (path,
|
1498
|
-
if (!/^([a-z-]+:)?\//.test(path) &&
|
1499
|
-
path =
|
1594
|
+
less.Parser.importer = function (path, currentFileInfo, callback, env) {
|
1595
|
+
if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) {
|
1596
|
+
path = currentFileInfo.currentDirectory + path;
|
1500
1597
|
}
|
1598
|
+
var sheetEnv = env.toSheet(path);
|
1599
|
+
sheetEnv.processImports = false;
|
1600
|
+
sheetEnv.currentFileInfo = currentFileInfo;
|
1601
|
+
|
1501
1602
|
// We pass `true` as 3rd argument, to force the reload of the import.
|
1502
1603
|
// This is so we can get the syntax tree as opposed to just the CSS output,
|
1503
1604
|
// as we need this to evaluate the current stylesheet.
|
1504
|
-
loadStyleSheet(
|
1505
|
-
|
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) {
|
1514
|
-
if (e && typeof(env.errback) === "function") {
|
1515
|
-
env.errback.call(null, path, paths, callback, env);
|
1516
|
-
} else {
|
1605
|
+
loadStyleSheet(sheetEnv,
|
1606
|
+
function (e, root, data, sheet, _, path) {
|
1517
1607
|
callback.call(null, e, root, path);
|
1518
|
-
}
|
1519
|
-
}, true);
|
1608
|
+
}, true);
|
1520
1609
|
};
|
1521
1610
|
}
|
1522
1611
|
|