less 2.3.3 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|