less 2.1.2 → 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.
- package/.idea/inspectionProfiles/Project_Default.xml +1 -0
- package/.idea/jsLinters/jscs.xml +4 -0
- package/.idea/jsLinters/jshint.xml +58 -4
- package/.idea/workspace.xml +499 -760
- package/.jscsrc +73 -0
- package/.jshintrc +0 -2
- package/.travis.yml +1 -0
- package/CHANGELOG.md +59 -0
- package/Gruntfile.js +37 -3
- package/appveyor.yml +5 -0
- package/bin/lessc +383 -316
- package/bower.json +1 -1
- package/dist/less.js +1638 -1244
- package/dist/less.min.js +7 -7
- package/lib/less/contexts.js +3 -3
- package/lib/less/data/unit-conversions.js +3 -3
- package/lib/less/environment/abstract-file-manager.js +8 -8
- package/lib/less/environment/environment.js +2 -2
- package/lib/less/functions/color-blending.js +3 -3
- package/lib/less/functions/color.js +20 -12
- package/lib/less/functions/data-uri.js +26 -18
- package/lib/less/functions/math.js +1 -1
- package/lib/less/functions/number.js +2 -2
- package/lib/less/functions/string.js +3 -1
- package/lib/less/functions/svg.js +12 -15
- package/lib/less/functions/types.js +33 -10
- package/lib/less/import-manager.js +14 -9
- package/lib/less/index.js +2 -1
- package/lib/less/less-error.js +1 -1
- package/lib/less/logger.js +2 -2
- package/lib/less/parse-tree.js +48 -42
- package/lib/less/parse.js +68 -0
- package/lib/less/parser/parser-input.js +6 -5
- package/lib/less/parser/parser.js +76 -29
- package/lib/less/plugin-manager.js +30 -3
- package/lib/less/render.js +11 -37
- package/lib/less/source-map-builder.js +4 -0
- package/lib/less/source-map-output.js +6 -6
- package/lib/less/transform-tree.js +4 -4
- package/lib/less/tree/anonymous.js +1 -1
- package/lib/less/tree/assignment.js +0 -1
- package/lib/less/tree/call.js +1 -1
- package/lib/less/tree/color.js +6 -6
- package/lib/less/tree/condition.js +9 -5
- package/lib/less/tree/debug-info.js +6 -2
- package/lib/less/tree/dimension.js +5 -5
- package/lib/less/tree/directive.js +25 -6
- package/lib/less/tree/element.js +1 -1
- package/lib/less/tree/expression.js +2 -2
- package/lib/less/tree/extend.js +3 -3
- package/lib/less/tree/import.js +2 -2
- package/lib/less/tree/index.js +1 -0
- package/lib/less/tree/javascript.js +2 -2
- package/lib/less/tree/media.js +20 -19
- package/lib/less/tree/mixin-call.js +5 -6
- package/lib/less/tree/mixin-definition.js +33 -11
- package/lib/less/tree/quoted.js +3 -3
- package/lib/less/tree/rule.js +3 -4
- package/lib/less/tree/ruleset.js +290 -177
- package/lib/less/tree/selector.js +3 -2
- package/lib/less/tree/unit.js +2 -0
- package/lib/less/tree/url.js +5 -2
- package/lib/less/tree/value.js +2 -2
- package/lib/less/tree/variable.js +1 -1
- package/lib/less/visitors/extend-visitor.js +72 -36
- package/lib/less/visitors/import-sequencer.js +20 -14
- package/lib/less/visitors/import-visitor.js +15 -12
- package/lib/less/visitors/to-css-visitor.js +41 -9
- package/lib/less-browser/add-default-options.js +5 -1
- package/lib/less-browser/bootstrap.js +10 -8
- package/lib/less-browser/cache.js +3 -3
- package/lib/less-browser/file-manager.js +96 -96
- package/lib/less-browser/index.js +206 -205
- package/lib/less-browser/log-listener.js +2 -2
- package/lib/less-browser/utils.js +6 -6
- package/lib/less-node/file-manager.js +58 -30
- package/lib/less-node/image-size.js +34 -0
- package/lib/less-node/index.js +6 -3
- package/lib/less-node/lessc-helper.js +3 -2
- package/lib/less-node/plugin-loader.js +3 -3
- package/lib/less-node/url-file-manager.js +6 -3
- package/lib/less-rhino/index.js +15 -13
- package/lib/source-map/source-map-0.1.31.js +1 -1
- package/package.json +10 -7
- package/test/browser/common.js +13 -11
- package/test/browser/css/relative-urls/urls.css +1 -0
- package/test/browser/css/urls.css +6 -3
- package/test/browser/jasmine-jsreporter.js +2 -3
- package/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
- package/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
- package/test/browser/less/relative-urls/urls.less +1 -0
- package/test/browser/less/urls.less +1 -0
- package/test/browser/runner-browser-options.js +23 -23
- package/test/browser/runner-errors-options.js +0 -1
- package/test/browser/runner-errors-spec.js +1 -2
- package/test/browser/runner-global-vars-spec.js +1 -1
- package/test/browser/runner-legacy-options.js +0 -1
- package/test/browser/runner-main-options.js +5 -5
- package/test/browser/runner-main-spec.js +1 -1
- package/test/browser/runner-no-js-errors-spec.js +0 -1
- package/test/browser/runner-production-options.js +0 -1
- package/test/browser/runner-relative-urls-options.js +0 -1
- package/test/browser/runner-rootpath-options.js +0 -1
- package/test/browser/runner-rootpath-relative-options.js +0 -1
- package/test/browser/runner-strict-units-options.js +0 -1
- package/test/copy-bom.js +72 -0
- package/test/css/comments.css +1 -0
- package/test/css/css-3.css +2 -0
- package/test/css/functions.css +10 -0
- package/test/css/import-interpolation.css +7 -0
- package/test/css/import-reference.css +25 -0
- package/test/css/include-path/include-path.css +6 -0
- package/test/css/mixins-important.css +12 -0
- package/test/css/selectors.css +15 -1
- package/test/css/static-urls/urls.css +1 -0
- package/test/css/url-args/urls.css +3 -3
- package/test/css/urls.css +13 -4
- package/test/css/variables.css +7 -1
- package/test/data/image.svg +3 -0
- package/test/index.js +15 -10
- package/test/less/comments.less +1 -0
- package/test/less/css-3.less +3 -0
- package/test/less/css-guards.less +2 -1
- package/test/less/errors/detached-ruleset-2.txt +1 -1
- package/test/less/errors/import-missing.txt +1 -1
- package/test/less/errors/parens-error-1.txt +1 -1
- package/test/less/errors/parens-error-2.txt +1 -1
- package/test/less/errors/parens-error-3.txt +1 -1
- package/test/less/errors/single-character.less +1 -0
- package/test/less/errors/single-character.txt +2 -0
- package/test/less/functions.less +18 -0
- package/test/less/import/import-interpolation.less +1 -0
- package/test/less/import/import-reference.less +38 -0
- package/test/less/import/imports/logo.less +1 -0
- package/test/less/import-reference.less +3 -1
- package/test/less/import.less +2 -0
- package/test/less/include-path/include-path.less +6 -0
- package/test/less/mixins-important.less +28 -0
- package/test/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
- package/test/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
- package/test/less/selectors.less +29 -4
- package/test/less/sourcemaps-empty/empty.less +0 -0
- package/test/less/sourcemaps-empty/var-defs.less +1 -0
- package/test/less/urls.less +10 -1
- package/test/less/variables.less +17 -3
- package/test/less-test.js +133 -52
- package/test/modify-vars.js +14 -12
- package/test/browser/less.js +0 -9473
package/lib/less/parse-tree.js
CHANGED
|
@@ -1,54 +1,60 @@
|
|
|
1
1
|
var LessError = require('./less-error'),
|
|
2
|
-
transformTree = require("./transform-tree")
|
|
2
|
+
transformTree = require("./transform-tree"),
|
|
3
|
+
logger = require("./logger");
|
|
3
4
|
|
|
4
5
|
module.exports = function(SourceMapBuilder) {
|
|
5
|
-
var ParseTree = function(root, imports) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
6
|
+
var ParseTree = function(root, imports) {
|
|
7
|
+
this.root = root;
|
|
8
|
+
this.imports = imports;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
ParseTree.prototype.toCSS = function(options) {
|
|
12
|
+
var evaldRoot, result = {}, sourceMapBuilder;
|
|
13
|
+
try {
|
|
14
|
+
evaldRoot = transformTree(this.root, options);
|
|
15
|
+
} catch (e) {
|
|
16
|
+
throw new LessError(e, this.imports);
|
|
17
|
+
}
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
throw new LessError(e, this.imports);
|
|
16
|
-
}
|
|
19
|
+
try {
|
|
20
|
+
var compress = Boolean(options.compress);
|
|
21
|
+
if (compress) {
|
|
22
|
+
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
|
|
23
|
+
}
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
numPrecision: 8};
|
|
25
|
+
var toCSSOptions = {
|
|
26
|
+
compress: compress,
|
|
27
|
+
dumpLineNumbers: options.dumpLineNumbers,
|
|
28
|
+
strictUnits: Boolean(options.strictUnits),
|
|
29
|
+
numPrecision: 8};
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
if (options.sourceMap) {
|
|
32
|
+
sourceMapBuilder = new SourceMapBuilder(options.sourceMap);
|
|
33
|
+
result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);
|
|
34
|
+
} else {
|
|
35
|
+
result.css = evaldRoot.toCSS(toCSSOptions);
|
|
36
|
+
}
|
|
37
|
+
} catch (e) {
|
|
38
|
+
throw new LessError(e, this.imports);
|
|
30
39
|
}
|
|
31
|
-
} catch (e) {
|
|
32
|
-
throw new LessError(e, this.imports);
|
|
33
|
-
}
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
if (options.pluginManager) {
|
|
42
|
+
var postProcessors = options.pluginManager.getPostProcessors();
|
|
43
|
+
for (var i = 0; i < postProcessors.length; i++) {
|
|
44
|
+
result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (options.sourceMap) {
|
|
48
|
+
result.map = sourceMapBuilder.getExternalSourceMap();
|
|
39
49
|
}
|
|
40
|
-
}
|
|
41
|
-
if (options.sourceMap) {
|
|
42
|
-
result.map = sourceMapBuilder.getExternalSourceMap();
|
|
43
|
-
}
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
result.imports = [];
|
|
52
|
+
for (var file in this.imports.files) {
|
|
53
|
+
if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) {
|
|
54
|
+
result.imports.push(file);
|
|
55
|
+
}
|
|
49
56
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return ParseTree;
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
return ParseTree;
|
|
54
60
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var PromiseConstructor,
|
|
2
|
+
contexts = require("./contexts"),
|
|
3
|
+
Parser = require('./parser/parser'),
|
|
4
|
+
PluginManager = require('./plugin-manager');
|
|
5
|
+
|
|
6
|
+
module.exports = function(environment, ParseTree, ImportManager) {
|
|
7
|
+
var parse = function (input, options, callback) {
|
|
8
|
+
options = options || {};
|
|
9
|
+
|
|
10
|
+
if (typeof options === 'function') {
|
|
11
|
+
callback = options;
|
|
12
|
+
options = {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
if (!PromiseConstructor) {
|
|
17
|
+
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
|
|
18
|
+
}
|
|
19
|
+
var self = this;
|
|
20
|
+
return new PromiseConstructor(function (resolve, reject) {
|
|
21
|
+
parse.call(self, input, options, function(err, output) {
|
|
22
|
+
if (err) {
|
|
23
|
+
reject(err);
|
|
24
|
+
} else {
|
|
25
|
+
resolve(output);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
var context,
|
|
31
|
+
rootFileInfo,
|
|
32
|
+
pluginManager = new PluginManager(this);
|
|
33
|
+
|
|
34
|
+
pluginManager.addPlugins(options.plugins);
|
|
35
|
+
options.pluginManager = pluginManager;
|
|
36
|
+
|
|
37
|
+
context = new contexts.Parse(options);
|
|
38
|
+
|
|
39
|
+
if (options.rootFileInfo) {
|
|
40
|
+
rootFileInfo = options.rootFileInfo;
|
|
41
|
+
} else {
|
|
42
|
+
var filename = options.filename || "input";
|
|
43
|
+
var entryPath = filename.replace(/[^\/\\]*$/, "");
|
|
44
|
+
rootFileInfo = {
|
|
45
|
+
filename: filename,
|
|
46
|
+
relativeUrls: context.relativeUrls,
|
|
47
|
+
rootpath: context.rootpath || "",
|
|
48
|
+
currentDirectory: entryPath,
|
|
49
|
+
entryPath: entryPath,
|
|
50
|
+
rootFilename: filename
|
|
51
|
+
};
|
|
52
|
+
// add in a missing trailing slash
|
|
53
|
+
if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== "/") {
|
|
54
|
+
rootFileInfo.rootpath += "/";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var imports = new ImportManager(context, rootFileInfo);
|
|
59
|
+
|
|
60
|
+
new Parser(context, imports, rootFileInfo)
|
|
61
|
+
.parse(input, function (e, root) {
|
|
62
|
+
if (e) { return callback(e); }
|
|
63
|
+
callback(null, root, imports, options);
|
|
64
|
+
}, options);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return parse;
|
|
68
|
+
};
|
|
@@ -16,7 +16,8 @@ module.exports = function() {
|
|
|
16
16
|
saveStack.push( { current: current, i: parserInput.i, j: j });
|
|
17
17
|
};
|
|
18
18
|
parserInput.restore = function(possibleErrorMessage) {
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {
|
|
20
21
|
furthest = parserInput.i;
|
|
21
22
|
furthestPossibleErrorMessage = possibleErrorMessage;
|
|
22
23
|
}
|
|
@@ -72,7 +73,7 @@ module.exports = function() {
|
|
|
72
73
|
//
|
|
73
74
|
skipWhitespace(length);
|
|
74
75
|
|
|
75
|
-
if(typeof
|
|
76
|
+
if (typeof match === 'string') {
|
|
76
77
|
return match;
|
|
77
78
|
} else {
|
|
78
79
|
return match.length === 1 ? match[0] : match;
|
|
@@ -91,7 +92,7 @@ module.exports = function() {
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
skipWhitespace(m[0].length);
|
|
94
|
-
if(typeof m === "string") {
|
|
95
|
+
if (typeof m === "string") {
|
|
95
96
|
return m;
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -184,7 +185,7 @@ module.exports = function() {
|
|
|
184
185
|
// Same as $(), but don't change the state of the parser,
|
|
185
186
|
// just return the match.
|
|
186
187
|
parserInput.peek = function(tok) {
|
|
187
|
-
if (typeof
|
|
188
|
+
if (typeof tok === 'string') {
|
|
188
189
|
return input.charAt(parserInput.i) === tok;
|
|
189
190
|
} else {
|
|
190
191
|
return tok.test(current);
|
|
@@ -238,7 +239,7 @@ module.exports = function() {
|
|
|
238
239
|
|
|
239
240
|
parserInput.end = function() {
|
|
240
241
|
var message,
|
|
241
|
-
isFinished = parserInput.i >= input.length
|
|
242
|
+
isFinished = parserInput.i >= input.length;
|
|
242
243
|
|
|
243
244
|
if (parserInput.i < furthest) {
|
|
244
245
|
message = furthestPossibleErrorMessage;
|
|
@@ -47,7 +47,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
47
47
|
if (result) {
|
|
48
48
|
return result;
|
|
49
49
|
}
|
|
50
|
-
error(msg || (typeof
|
|
50
|
+
error(msg || (typeof arg === 'string' ? "expected '" + arg + "' got '" + parserInput.currentChar() + "'"
|
|
51
51
|
: "unexpected token"));
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -92,17 +92,26 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
92
92
|
// @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
|
|
93
93
|
//
|
|
94
94
|
parse: function (str, callback, additionalData) {
|
|
95
|
-
var root, error = null, globalVars, modifyVars, preText = "";
|
|
95
|
+
var root, error = null, globalVars, modifyVars, ignored, preText = "";
|
|
96
96
|
|
|
97
97
|
globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : '';
|
|
98
98
|
modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : '';
|
|
99
99
|
|
|
100
|
+
if (context.pluginManager) {
|
|
101
|
+
var preProcessors = context.pluginManager.getPreProcessors();
|
|
102
|
+
for (var i = 0; i < preProcessors.length; i++) {
|
|
103
|
+
str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
100
107
|
if (globalVars || (additionalData && additionalData.banner)) {
|
|
101
108
|
preText = ((additionalData && additionalData.banner) ? additionalData.banner : "") + globalVars;
|
|
102
|
-
|
|
109
|
+
ignored = imports.contentsIgnoredChars;
|
|
110
|
+
ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
|
|
111
|
+
ignored[fileInfo.filename] += preText.length;
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
str = str.replace(/\r\n
|
|
114
|
+
str = str.replace(/\r\n?/g, '\n');
|
|
106
115
|
// Remove potential UTF Byte Order Mark
|
|
107
116
|
str = preText + str.replace(/^\uFEFF/, '') + modifyVars;
|
|
108
117
|
imports.contents[fileInfo.filename] = str;
|
|
@@ -204,7 +213,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
204
213
|
// Ruleset (Selector '.class', [
|
|
205
214
|
// Rule ("color", Value ([Expression [Color #fff]]))
|
|
206
215
|
// Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
|
|
207
|
-
// Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
|
|
216
|
+
// Rule ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]]))
|
|
208
217
|
// Ruleset (Selector [Element '>', '.child'], [...])
|
|
209
218
|
// ])
|
|
210
219
|
//
|
|
@@ -231,13 +240,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
231
240
|
primary: function () {
|
|
232
241
|
var mixin = this.mixin, root = [], node;
|
|
233
242
|
|
|
234
|
-
while (
|
|
243
|
+
while (true)
|
|
235
244
|
{
|
|
236
|
-
while(true) {
|
|
245
|
+
while (true) {
|
|
237
246
|
node = this.comment();
|
|
238
247
|
if (!node) { break; }
|
|
239
248
|
root.push(node);
|
|
240
249
|
}
|
|
250
|
+
// always process comments before deciding if finished
|
|
251
|
+
if (parserInput.finished) {
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
241
254
|
if (parserInput.peek('}')) {
|
|
242
255
|
break;
|
|
243
256
|
}
|
|
@@ -328,7 +341,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
328
341
|
|
|
329
342
|
if (nameLC === 'alpha') {
|
|
330
343
|
alpha = parsers.alpha();
|
|
331
|
-
if(alpha) {
|
|
344
|
+
if (alpha) {
|
|
332
345
|
return alpha;
|
|
333
346
|
}
|
|
334
347
|
}
|
|
@@ -450,7 +463,9 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
450
463
|
var rgb;
|
|
451
464
|
|
|
452
465
|
if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
|
|
453
|
-
|
|
466
|
+
// strip colons, brackets, whitespaces and other characters that should not
|
|
467
|
+
// definitely be part of color string
|
|
468
|
+
var colorCandidateString = rgb.input.match(/^#([\w]+).*/);
|
|
454
469
|
colorCandidateString = colorCandidateString[1];
|
|
455
470
|
if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
|
|
456
471
|
error("Invalid HEX color code");
|
|
@@ -541,17 +556,27 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
541
556
|
elements = null;
|
|
542
557
|
while (! (option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) {
|
|
543
558
|
e = this.element();
|
|
544
|
-
if (!e) {
|
|
545
|
-
|
|
559
|
+
if (!e) {
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
if (elements) {
|
|
563
|
+
elements.push(e);
|
|
564
|
+
} else {
|
|
565
|
+
elements = [ e ];
|
|
566
|
+
}
|
|
546
567
|
}
|
|
547
568
|
|
|
548
569
|
option = option && option[1];
|
|
549
|
-
if (!elements)
|
|
570
|
+
if (!elements) {
|
|
550
571
|
error("Missing target selector for :extend().");
|
|
572
|
+
}
|
|
551
573
|
extend = new(tree.Extend)(new(tree.Selector)(elements), option, index);
|
|
552
|
-
if (extendList) {
|
|
553
|
-
|
|
554
|
-
|
|
574
|
+
if (extendList) {
|
|
575
|
+
extendList.push(extend);
|
|
576
|
+
} else {
|
|
577
|
+
extendList = [ extend ];
|
|
578
|
+
}
|
|
579
|
+
} while (parserInput.$char(","));
|
|
555
580
|
|
|
556
581
|
expect(/^\)/);
|
|
557
582
|
|
|
@@ -599,7 +624,11 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
599
624
|
break;
|
|
600
625
|
}
|
|
601
626
|
elem = new(tree.Element)(c, e, elemIndex, fileInfo);
|
|
602
|
-
if (elements) {
|
|
627
|
+
if (elements) {
|
|
628
|
+
elements.push(elem);
|
|
629
|
+
} else {
|
|
630
|
+
elements = [ elem ];
|
|
631
|
+
}
|
|
603
632
|
c = parserInput.$char('>');
|
|
604
633
|
}
|
|
605
634
|
|
|
@@ -857,8 +886,10 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
857
886
|
|
|
858
887
|
c = this.combinator();
|
|
859
888
|
|
|
860
|
-
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
|
|
861
|
-
parserInput.$
|
|
889
|
+
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
|
|
890
|
+
parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
|
891
|
+
parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
|
|
892
|
+
parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
|
|
862
893
|
this.entities.variableCurly();
|
|
863
894
|
|
|
864
895
|
if (! e) {
|
|
@@ -938,11 +969,19 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
938
969
|
} else if (condition) {
|
|
939
970
|
error("CSS guard can only be used at the end of selector");
|
|
940
971
|
} else if (extendList) {
|
|
941
|
-
if (allExtends) {
|
|
972
|
+
if (allExtends) {
|
|
973
|
+
allExtends = allExtends.concat(extendList);
|
|
974
|
+
} else {
|
|
975
|
+
allExtends = extendList;
|
|
976
|
+
}
|
|
942
977
|
} else {
|
|
943
978
|
if (allExtends) { error("Extend can only be used at the end of selector"); }
|
|
944
979
|
c = parserInput.currentChar();
|
|
945
|
-
if (elements) {
|
|
980
|
+
if (elements) {
|
|
981
|
+
elements.push(e);
|
|
982
|
+
} else {
|
|
983
|
+
elements = [ e ];
|
|
984
|
+
}
|
|
946
985
|
e = null;
|
|
947
986
|
}
|
|
948
987
|
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
|
|
@@ -1017,7 +1056,11 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1017
1056
|
if (!s) {
|
|
1018
1057
|
break;
|
|
1019
1058
|
}
|
|
1020
|
-
if (selectors) {
|
|
1059
|
+
if (selectors) {
|
|
1060
|
+
selectors.push(s);
|
|
1061
|
+
} else {
|
|
1062
|
+
selectors = [ s ];
|
|
1063
|
+
}
|
|
1021
1064
|
parserInput.commentStore.length = 0;
|
|
1022
1065
|
if (s.condition && selectors.length > 1) {
|
|
1023
1066
|
error("Guards are only currently allowed on a single selector.");
|
|
@@ -1154,11 +1197,11 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1154
1197
|
case "css":
|
|
1155
1198
|
optionName = "less";
|
|
1156
1199
|
value = false;
|
|
1157
|
-
|
|
1200
|
+
break;
|
|
1158
1201
|
case "once":
|
|
1159
1202
|
optionName = "multiple";
|
|
1160
1203
|
value = false;
|
|
1161
|
-
|
|
1204
|
+
break;
|
|
1162
1205
|
}
|
|
1163
1206
|
options[optionName] = value;
|
|
1164
1207
|
if (! parserInput.$char(',')) { break; }
|
|
@@ -1169,7 +1212,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1169
1212
|
},
|
|
1170
1213
|
|
|
1171
1214
|
importOption: function() {
|
|
1172
|
-
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference)/);
|
|
1215
|
+
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
|
|
1173
1216
|
if (opt) {
|
|
1174
1217
|
return opt[1];
|
|
1175
1218
|
}
|
|
@@ -1369,7 +1412,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1369
1412
|
expressions.push(e);
|
|
1370
1413
|
if (! parserInput.$char(',')) { break; }
|
|
1371
1414
|
}
|
|
1372
|
-
} while(e);
|
|
1415
|
+
} while (e);
|
|
1373
1416
|
|
|
1374
1417
|
if (expressions.length > 0) {
|
|
1375
1418
|
return new(tree.Value)(expressions);
|
|
@@ -1383,15 +1426,19 @@ var Parser = function Parser(context, imports, fileInfo) {
|
|
|
1383
1426
|
sub: function () {
|
|
1384
1427
|
var a, e;
|
|
1385
1428
|
|
|
1429
|
+
parserInput.save();
|
|
1386
1430
|
if (parserInput.$char('(')) {
|
|
1387
1431
|
a = this.addition();
|
|
1388
|
-
if (a) {
|
|
1432
|
+
if (a && parserInput.$char(')')) {
|
|
1433
|
+
parserInput.forget();
|
|
1389
1434
|
e = new(tree.Expression)([a]);
|
|
1390
|
-
expectChar(')');
|
|
1391
1435
|
e.parens = true;
|
|
1392
1436
|
return e;
|
|
1393
1437
|
}
|
|
1438
|
+
parserInput.restore("Expected ')'");
|
|
1439
|
+
return;
|
|
1394
1440
|
}
|
|
1441
|
+
parserInput.restore();
|
|
1395
1442
|
},
|
|
1396
1443
|
multiplication: function () {
|
|
1397
1444
|
var m, a, op, operation, isSpaced;
|
|
@@ -1598,8 +1645,8 @@ Parser.serializeVars = function(vars) {
|
|
|
1598
1645
|
for (var name in vars) {
|
|
1599
1646
|
if (Object.hasOwnProperty.call(vars, name)) {
|
|
1600
1647
|
var value = vars[name];
|
|
1601
|
-
s += ((name[0] === '@') ? '' : '@') + name +': '+ value +
|
|
1602
|
-
(((
|
|
1648
|
+
s += ((name[0] === '@') ? '' : '@') + name + ': ' + value +
|
|
1649
|
+
((String(value).slice(-1) === ';') ? '' : ';');
|
|
1603
1650
|
}
|
|
1604
1651
|
}
|
|
1605
1652
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var PluginManager = function(less) {
|
|
5
5
|
this.less = less;
|
|
6
6
|
this.visitors = [];
|
|
7
|
+
this.preProcessors = [];
|
|
7
8
|
this.postProcessors = [];
|
|
8
9
|
this.installedPlugins = [];
|
|
9
10
|
this.fileManagers = [];
|
|
@@ -14,7 +15,7 @@ var PluginManager = function(less) {
|
|
|
14
15
|
*/
|
|
15
16
|
PluginManager.prototype.addPlugins = function(plugins) {
|
|
16
17
|
if (plugins) {
|
|
17
|
-
for(var i = 0;i < plugins.length; i++) {
|
|
18
|
+
for (var i = 0; i < plugins.length; i++) {
|
|
18
19
|
this.addPlugin(plugins[i]);
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -35,6 +36,20 @@ PluginManager.prototype.addPlugin = function(plugin) {
|
|
|
35
36
|
PluginManager.prototype.addVisitor = function(visitor) {
|
|
36
37
|
this.visitors.push(visitor);
|
|
37
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Adds a pre processor object
|
|
41
|
+
* @param {object} preProcessor
|
|
42
|
+
* @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import
|
|
43
|
+
*/
|
|
44
|
+
PluginManager.prototype.addPreProcessor = function(preProcessor, priority) {
|
|
45
|
+
var indexToInsertAt;
|
|
46
|
+
for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) {
|
|
47
|
+
if (this.preProcessors[indexToInsertAt].priority >= priority) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority});
|
|
52
|
+
};
|
|
38
53
|
/**
|
|
39
54
|
* Adds a post processor object
|
|
40
55
|
* @param {object} postProcessor
|
|
@@ -42,7 +57,7 @@ PluginManager.prototype.addVisitor = function(visitor) {
|
|
|
42
57
|
*/
|
|
43
58
|
PluginManager.prototype.addPostProcessor = function(postProcessor, priority) {
|
|
44
59
|
var indexToInsertAt;
|
|
45
|
-
for(indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {
|
|
60
|
+
for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {
|
|
46
61
|
if (this.postProcessors[indexToInsertAt].priority >= priority) {
|
|
47
62
|
break;
|
|
48
63
|
}
|
|
@@ -56,6 +71,18 @@ PluginManager.prototype.addPostProcessor = function(postProcessor, priority) {
|
|
|
56
71
|
PluginManager.prototype.addFileManager = function(manager) {
|
|
57
72
|
this.fileManagers.push(manager);
|
|
58
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @returns {Array}
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
PluginManager.prototype.getPreProcessors = function() {
|
|
80
|
+
var preProcessors = [];
|
|
81
|
+
for (var i = 0; i < this.preProcessors.length; i++) {
|
|
82
|
+
preProcessors.push(this.preProcessors[i].preProcessor);
|
|
83
|
+
}
|
|
84
|
+
return preProcessors;
|
|
85
|
+
};
|
|
59
86
|
/**
|
|
60
87
|
*
|
|
61
88
|
* @returns {Array}
|
|
@@ -63,7 +90,7 @@ PluginManager.prototype.addFileManager = function(manager) {
|
|
|
63
90
|
*/
|
|
64
91
|
PluginManager.prototype.getPostProcessors = function() {
|
|
65
92
|
var postProcessors = [];
|
|
66
|
-
for(var i = 0; i < this.postProcessors.length; i++) {
|
|
93
|
+
for (var i = 0; i < this.postProcessors.length; i++) {
|
|
67
94
|
postProcessors.push(this.postProcessors[i].postProcessor);
|
|
68
95
|
}
|
|
69
96
|
return postProcessors;
|
package/lib/less/render.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
var PromiseConstructor
|
|
2
|
-
contexts = require("./contexts"),
|
|
3
|
-
Parser = require('./parser/parser'),
|
|
4
|
-
PluginManager = require('./plugin-manager');
|
|
1
|
+
var PromiseConstructor;
|
|
5
2
|
|
|
6
3
|
module.exports = function(environment, ParseTree, ImportManager) {
|
|
7
4
|
var render = function (input, options, callback) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof(options) === 'function') {
|
|
5
|
+
if (typeof options === 'function') {
|
|
11
6
|
callback = options;
|
|
12
7
|
options = {};
|
|
13
8
|
}
|
|
14
9
|
|
|
15
10
|
if (!callback) {
|
|
11
|
+
if (!PromiseConstructor) {
|
|
12
|
+
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
|
|
13
|
+
}
|
|
16
14
|
var self = this;
|
|
17
15
|
return new PromiseConstructor(function (resolve, reject) {
|
|
18
16
|
render.call(self, input, options, function(err, output) {
|
|
@@ -24,44 +22,20 @@ module.exports = function(environment, ParseTree, ImportManager) {
|
|
|
24
22
|
});
|
|
25
23
|
});
|
|
26
24
|
} else {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
pluginManager = new PluginManager(this);
|
|
30
|
-
|
|
31
|
-
pluginManager.addPlugins(options.plugins);
|
|
32
|
-
options.pluginManager = pluginManager;
|
|
33
|
-
|
|
34
|
-
context = new contexts.Parse(options);
|
|
35
|
-
|
|
36
|
-
if (options.rootFileInfo) {
|
|
37
|
-
rootFileInfo = options.rootFileInfo;
|
|
38
|
-
} else {
|
|
39
|
-
var filename = options.filename || "input";
|
|
40
|
-
var entryPath = filename.replace(/[^\/\\]*$/, "");
|
|
41
|
-
rootFileInfo = {
|
|
42
|
-
filename: filename,
|
|
43
|
-
relativeUrls: context.relativeUrls,
|
|
44
|
-
rootpath: context.rootpath || "",
|
|
45
|
-
currentDirectory: entryPath,
|
|
46
|
-
entryPath: entryPath,
|
|
47
|
-
rootFilename: filename
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
var imports = new ImportManager(context, rootFileInfo);
|
|
25
|
+
this.parse(input, options, function(err, root, imports, options) {
|
|
26
|
+
if (err) { return callback(err); }
|
|
52
27
|
|
|
53
|
-
new Parser(context, imports, rootFileInfo)
|
|
54
|
-
.parse(input, function (e, root) {
|
|
55
|
-
if (e) { return callback(e); }
|
|
56
28
|
var result;
|
|
57
29
|
try {
|
|
58
30
|
var parseTree = new ParseTree(root, imports);
|
|
59
31
|
result = parseTree.toCSS(options);
|
|
60
32
|
}
|
|
61
|
-
catch (err) { return callback(
|
|
33
|
+
catch (err) { return callback(err); }
|
|
34
|
+
|
|
62
35
|
callback(null, result);
|
|
63
|
-
}
|
|
36
|
+
});
|
|
64
37
|
}
|
|
65
38
|
};
|
|
39
|
+
|
|
66
40
|
return render;
|
|
67
41
|
};
|
|
@@ -30,8 +30,12 @@ module.exports = function (SourceMapOutput, environment) {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
SourceMapBuilder.prototype.getCSSAppendage = function() {
|
|
33
|
+
|
|
33
34
|
var sourceMapURL = this.sourceMapURL;
|
|
34
35
|
if (this.options.sourceMapFileInline) {
|
|
36
|
+
if (this.sourceMap === undefined) {
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
35
39
|
sourceMapURL = "data:application/json;base64," + environment.encodeBase64(this.sourceMap);
|
|
36
40
|
}
|
|
37
41
|
|
|
@@ -15,7 +15,7 @@ module.exports = function (environment) {
|
|
|
15
15
|
}
|
|
16
16
|
if (options.sourceMapRootpath) {
|
|
17
17
|
this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
|
|
18
|
-
if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1) !== '/') {
|
|
18
|
+
if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
|
|
19
19
|
this._sourceMapRootpath += '/';
|
|
20
20
|
}
|
|
21
21
|
} else {
|
|
@@ -34,7 +34,7 @@ module.exports = function (environment) {
|
|
|
34
34
|
if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
|
|
35
35
|
filename = filename.substring(this._sourceMapBasepath.length);
|
|
36
36
|
if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
|
|
37
|
-
|
|
37
|
+
filename = filename.substring(1);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
return (this._sourceMapRootpath || "") + filename;
|
|
@@ -66,11 +66,11 @@ module.exports = function (environment) {
|
|
|
66
66
|
}
|
|
67
67
|
inputSource = inputSource.substring(0, index);
|
|
68
68
|
sourceLines = inputSource.split("\n");
|
|
69
|
-
sourceColumns = sourceLines[sourceLines.length-1];
|
|
69
|
+
sourceColumns = sourceLines[sourceLines.length - 1];
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
lines = chunk.split("\n");
|
|
73
|
-
columns = lines[lines.length-1];
|
|
73
|
+
columns = lines[lines.length - 1];
|
|
74
74
|
|
|
75
75
|
if (fileInfo) {
|
|
76
76
|
if (!mapLines) {
|
|
@@ -78,7 +78,7 @@ module.exports = function (environment) {
|
|
|
78
78
|
original: { line: sourceLines.length, column: sourceColumns.length},
|
|
79
79
|
source: this.normalizeFilename(fileInfo.filename)});
|
|
80
80
|
} else {
|
|
81
|
-
for(i = 0; i < lines.length; i++) {
|
|
81
|
+
for (i = 0; i < lines.length; i++) {
|
|
82
82
|
this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
|
|
83
83
|
original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
|
|
84
84
|
source: this.normalizeFilename(fileInfo.filename)});
|
|
@@ -104,7 +104,7 @@ module.exports = function (environment) {
|
|
|
104
104
|
this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
|
|
105
105
|
|
|
106
106
|
if (this._outputSourceFiles) {
|
|
107
|
-
for(var filename in this._contentsMap) {
|
|
107
|
+
for (var filename in this._contentsMap) {
|
|
108
108
|
if (this._contentsMap.hasOwnProperty(filename))
|
|
109
109
|
{
|
|
110
110
|
var source = this._contentsMap[filename];
|