mirror of
https://github.com/less/less.js.git
synced 2026-01-23 14:18:00 -05:00
Merge https://github.com/less/less.js into nested-parent-selector-2026-v1
Conflicts: lib/less/parser/parser.js lib/less/tree/ruleset.js
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ test/browser/less.js
|
||||
test/sourcemaps/**/*.map
|
||||
test/sourcemaps/*.map
|
||||
test/sourcemaps/*.css
|
||||
test/less-bom
|
||||
|
||||
# grunt
|
||||
.grunt
|
||||
|
||||
38
.jscsrc
Normal file
38
.jscsrc
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"disallowImplicitTypeConversion": ["numeric", "boolean", "binary", "string"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowOperatorBeforeLineBreak": ["."],
|
||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~"],
|
||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowSpacesInNamedFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true},
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"maximumLineLength": 160,
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireCurlyBraces": [ "if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"try",
|
||||
"catch"],
|
||||
"requireOperatorBeforeLineBreak": [ "?",
|
||||
"=",
|
||||
"+",
|
||||
"-",
|
||||
"/",
|
||||
"*",
|
||||
"==",
|
||||
"===",
|
||||
"!=",
|
||||
"!==",
|
||||
">",
|
||||
">=",
|
||||
"<",
|
||||
"<="],
|
||||
"requireSpaceAfterBinaryOperators": true
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"evil": true,
|
||||
"laxbreak": true,
|
||||
"latedef": true,
|
||||
"node": true,
|
||||
"undef": true,
|
||||
"unused": "vars",
|
||||
"trailing": true,
|
||||
"noarg": true,
|
||||
"eqnull": true,
|
||||
"forin": true,
|
||||
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,3 +1,21 @@
|
||||
# 2.3.0
|
||||
|
||||
2015-01-27
|
||||
|
||||
- add isruleset function
|
||||
- add optional import option, causing less to not fail if file not found
|
||||
- Fix browsers-side cache.
|
||||
- Many fixes to import reference - support `@support` and keyframe
|
||||
- Selectors now interpolate pseudo selectors (e.g. `:@{hover}`)
|
||||
- Fix comments missed off if they were at the end of the file
|
||||
- Fix !important used with parametric mixins
|
||||
- Emits warnings for extends when the target is not found
|
||||
- include-path now works on data-uri
|
||||
- variables and function calls work for path in data-uri
|
||||
- Fix absolute paths not working on imports sometimes.
|
||||
- Unicode BOM removed again
|
||||
- Misc. bug fixes
|
||||
|
||||
# 2.2.0
|
||||
|
||||
2015-01-04
|
||||
|
||||
54
Gruntfile.js
54
Gruntfile.js
@@ -5,8 +5,8 @@ module.exports = function (grunt) {
|
||||
|
||||
// Report the elapsed execution time of tasks.
|
||||
require('time-grunt')(grunt);
|
||||
|
||||
var COMPRESS_FOR_TESTS = true;
|
||||
|
||||
var COMPRESS_FOR_TESTS = true;
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
@@ -96,18 +96,18 @@ module.exports = function (grunt) {
|
||||
options: {
|
||||
banner: '<%= meta.banner %>',
|
||||
mangle: true,
|
||||
compress: {
|
||||
pure_getters: true
|
||||
}
|
||||
compress: {
|
||||
pure_getters: true
|
||||
}
|
||||
},
|
||||
dist: {
|
||||
src: ['<%= concat.dist.dest %>'],
|
||||
dest: 'dist/less.min.js'
|
||||
},
|
||||
test: {
|
||||
src: '<%= browserify.browser.dest %>',
|
||||
dest: 'tmp/less.min.js'
|
||||
}
|
||||
test: {
|
||||
src: '<%= browserify.browser.dest %>',
|
||||
dest: 'tmp/less.min.js'
|
||||
}
|
||||
},
|
||||
|
||||
jshint: {
|
||||
@@ -124,6 +124,13 @@ module.exports = function (grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
jscs: {
|
||||
src: ["test/**/*.js", "lib/less*/**/*.js", "bin/lessc"],
|
||||
options: {
|
||||
config: ".jscsrc"
|
||||
}
|
||||
},
|
||||
|
||||
connect: {
|
||||
server: {
|
||||
options: {
|
||||
@@ -306,7 +313,7 @@ module.exports = function (grunt) {
|
||||
|
||||
// Clean the version of less built for the tests
|
||||
clean: {
|
||||
test: ['test/browser/less.js', 'tmp'],
|
||||
test: ['test/browser/less.js', 'tmp', 'test/less-bom'],
|
||||
"sourcemap-test": ['test/sourcemaps/*.css', 'test/sourcemaps/*.map'],
|
||||
sauce_log: ["sc_*.log"]
|
||||
}
|
||||
@@ -347,7 +354,7 @@ module.exports = function (grunt) {
|
||||
// Create the browser version of less.js
|
||||
grunt.registerTask('browsertest-lessjs', [
|
||||
'browserify:browser',
|
||||
'uglify:test',
|
||||
'uglify:test',
|
||||
'concat:browsertest'
|
||||
]);
|
||||
|
||||
@@ -365,19 +372,19 @@ module.exports = function (grunt) {
|
||||
'connect::keepalive'
|
||||
]);
|
||||
|
||||
var previous_force_state = grunt.option("force");
|
||||
var previous_force_state = grunt.option("force");
|
||||
|
||||
grunt.registerTask("force",function(set){
|
||||
if (set === "on") {
|
||||
grunt.option("force",true);
|
||||
}
|
||||
else if (set === "off") {
|
||||
grunt.option("force",false);
|
||||
}
|
||||
else if (set === "restore") {
|
||||
grunt.option("force",previous_force_state);
|
||||
}
|
||||
});
|
||||
grunt.registerTask("force",function(set){
|
||||
if (set === "on") {
|
||||
grunt.option("force",true);
|
||||
}
|
||||
else if (set === "off") {
|
||||
grunt.option("force",false);
|
||||
}
|
||||
else if (set === "restore") {
|
||||
grunt.option("force",previous_force_state);
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('sauce', [
|
||||
'browsertest-lessjs',
|
||||
@@ -395,6 +402,7 @@ module.exports = function (grunt) {
|
||||
var testTasks = [
|
||||
'clean',
|
||||
'jshint',
|
||||
'jscs',
|
||||
'shell:test',
|
||||
'browsertest'
|
||||
];
|
||||
|
||||
716
bin/lessc
716
bin/lessc
@@ -3,8 +3,15 @@
|
||||
var path = require('path'),
|
||||
fs = require('../lib/less-node/fs'),
|
||||
os = require('os'),
|
||||
errno,
|
||||
mkdirp;
|
||||
|
||||
try {
|
||||
errno = require('errno');
|
||||
} catch (err) {
|
||||
errno = null;
|
||||
}
|
||||
|
||||
var less = require('../lib/less-node'),
|
||||
pluginLoader = new less.PluginLoader(less),
|
||||
plugin,
|
||||
@@ -52,7 +59,7 @@ var checkArgFunc = function(arg, option) {
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
console.log(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
console.log(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
@@ -73,357 +80,406 @@ function printUsage() {
|
||||
continueProcessing = false;
|
||||
}
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match;
|
||||
// self executing function so we can return
|
||||
(function() {
|
||||
args = args.filter(function (arg) {
|
||||
var match;
|
||||
|
||||
match = arg.match(/^-I(.+)$/);
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; }
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
printUsage();
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'insecure':
|
||||
options.insecure = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
return path.resolve(process.cwd(), p);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
options.sourceMap = true;
|
||||
if (match[2]) {
|
||||
sourceMapOptions.sourceMapFullFilename = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
sourceMapOptions.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "global-var":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
if (!options.globalVars) {
|
||||
options.globalVars = {};
|
||||
}
|
||||
parseVariableOption(match[2], options.globalVars);
|
||||
}
|
||||
break;
|
||||
case "modify-var":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
if (!options.modifyVars) {
|
||||
options.modifyVars = {};
|
||||
}
|
||||
|
||||
parseVariableOption(match[2], options.modifyVars);
|
||||
}
|
||||
break;
|
||||
case 'url-args':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.urlArgs = match[2];
|
||||
}
|
||||
break;
|
||||
case 'plugin':
|
||||
var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
|
||||
name = splitupArg[1],
|
||||
pluginOptions = splitupArg[3];
|
||||
|
||||
plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
|
||||
if (plugin) {
|
||||
plugins.push(plugin);
|
||||
} else {
|
||||
console.log("Unable to load plugin " + name + " please make sure that it is installed under or at the same level as less");
|
||||
console.log();
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
|
||||
if (plugin) {
|
||||
plugins.push(plugin);
|
||||
} else {
|
||||
console.log("Unable to interpret argument " + arg + " - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at the same level as less");
|
||||
console.log();
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var input = args[1];
|
||||
if (input && input != '-') {
|
||||
input = path.resolve(process.cwd(), input);
|
||||
}
|
||||
var output = args[2];
|
||||
var outputbase = args[2];
|
||||
if (output) {
|
||||
output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.sourceMap) {
|
||||
|
||||
sourceMapOptions.sourceMapInputFilename = input;
|
||||
if (!sourceMapOptions.sourceMapFullFilename) {
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
console.log("consider adding --source-map-map-inline which embeds the sourcemap into the css");
|
||||
return;
|
||||
match = arg.match(/^-I(.+)$/);
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
// its in the same directory, so always just the basename
|
||||
sourceMapOptions.sourceMapOutputFilename = path.basename(output);
|
||||
sourceMapOptions.sourceMapFullFilename = output + ".map";
|
||||
// its in the same directory, so always just the basename
|
||||
sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
|
||||
} else if (options.sourceMap && !sourceMapFileInline) {
|
||||
var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
|
||||
mapDir = path.dirname(mapFilename),
|
||||
outputDir = path.dirname(output);
|
||||
// find the path from the map to the output file
|
||||
sourceMapOptions.sourceMapOutputFilename = path.join(
|
||||
path.relative(mapDir, outputDir), path.basename(output));
|
||||
|
||||
// make the sourcemap filename point to the sourcemap relative to the css file output directory
|
||||
sourceMapOptions.sourceMapFilename = path.join(
|
||||
path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
|
||||
}
|
||||
}
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; }
|
||||
else { return arg; }
|
||||
|
||||
if (sourceMapOptions.sourceMapBasepath === undefined) {
|
||||
sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
|
||||
}
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
printUsage();
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'insecure':
|
||||
options.insecure = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
return path.resolve(process.cwd(), p);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
options.sourceMap = true;
|
||||
if (match[2]) {
|
||||
sourceMapOptions.sourceMapFullFilename = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
sourceMapOptions.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
sourceMapOptions.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "global-var":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
if (!options.globalVars) {
|
||||
options.globalVars = {};
|
||||
}
|
||||
parseVariableOption(match[2], options.globalVars);
|
||||
}
|
||||
break;
|
||||
case "modify-var":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
if (!options.modifyVars) {
|
||||
options.modifyVars = {};
|
||||
}
|
||||
|
||||
if (sourceMapOptions.sourceMapRootpath === undefined) {
|
||||
var pathToMap = path.dirname(sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename),
|
||||
pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename);
|
||||
sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
|
||||
}
|
||||
parseVariableOption(match[2], options.modifyVars);
|
||||
}
|
||||
break;
|
||||
case 'url-args':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.urlArgs = match[2];
|
||||
}
|
||||
break;
|
||||
case 'plugin':
|
||||
var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
|
||||
name = splitupArg[1],
|
||||
pluginOptions = splitupArg[3];
|
||||
|
||||
|
||||
if (! input) {
|
||||
console.log("lessc: no input files");
|
||||
console.log("");
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var ensureDirectory = function (filepath) {
|
||||
var dir = path.dirname(filepath),
|
||||
cmd,
|
||||
existsSync = fs.existsSync || path.existsSync;
|
||||
if (!existsSync(dir)) {
|
||||
if (mkdirp === undefined) {
|
||||
try {mkdirp = require('mkdirp');}
|
||||
catch(e) { mkdirp = null; }
|
||||
plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
|
||||
if (plugin) {
|
||||
plugins.push(plugin);
|
||||
} else {
|
||||
console.log("Unable to load plugin " + name +
|
||||
" please make sure that it is installed under or at the same level as less");
|
||||
console.log();
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
|
||||
if (plugin) {
|
||||
plugins.push(plugin);
|
||||
} else {
|
||||
console.log("Unable to interpret argument " + arg +
|
||||
" - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at" +
|
||||
" the same level as less");
|
||||
console.log();
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
cmd(dir);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
process.stdout.write(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!sourceMapFileInline) {
|
||||
var writeSourceMap = function(output) {
|
||||
var filename = sourceMapOptions.sourceMapFullFilename;
|
||||
ensureDirectory(filename);
|
||||
fs.writeFileSync(filename, output, 'utf8');
|
||||
};
|
||||
}
|
||||
var input = args[1];
|
||||
if (input && input != '-') {
|
||||
input = path.resolve(process.cwd(), input);
|
||||
}
|
||||
var output = args[2];
|
||||
var outputbase = args[2];
|
||||
if (output) {
|
||||
output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
var parseLessFile = function (e, data) {
|
||||
if (e) {
|
||||
console.log("lessc: " + e.message);
|
||||
if (options.sourceMap) {
|
||||
|
||||
sourceMapOptions.sourceMapInputFilename = input;
|
||||
if (!sourceMapOptions.sourceMapFullFilename) {
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
console.log("consider adding --source-map-map-inline which embeds the sourcemap into the css");
|
||||
return;
|
||||
}
|
||||
// its in the same directory, so always just the basename
|
||||
sourceMapOptions.sourceMapOutputFilename = path.basename(output);
|
||||
sourceMapOptions.sourceMapFullFilename = output + ".map";
|
||||
// its in the same directory, so always just the basename
|
||||
sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
|
||||
} else if (options.sourceMap && !sourceMapFileInline) {
|
||||
var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
|
||||
mapDir = path.dirname(mapFilename),
|
||||
outputDir = path.dirname(output);
|
||||
// find the path from the map to the output file
|
||||
sourceMapOptions.sourceMapOutputFilename = path.join(
|
||||
path.relative(mapDir, outputDir), path.basename(output));
|
||||
|
||||
// make the sourcemap filename point to the sourcemap relative to the css file output directory
|
||||
sourceMapOptions.sourceMapFilename = path.join(
|
||||
path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceMapOptions.sourceMapBasepath === undefined) {
|
||||
sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
|
||||
}
|
||||
|
||||
if (sourceMapOptions.sourceMapRootpath === undefined) {
|
||||
var pathToMap = path.dirname(sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename),
|
||||
pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename);
|
||||
sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
|
||||
}
|
||||
|
||||
if (! input) {
|
||||
console.log("lessc: no input files");
|
||||
console.log("");
|
||||
printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
options.paths = [path.dirname(input)].concat(options.paths);
|
||||
options.filename = input;
|
||||
var ensureDirectory = function (filepath) {
|
||||
var dir = path.dirname(filepath),
|
||||
cmd,
|
||||
existsSync = fs.existsSync || path.existsSync;
|
||||
if (!existsSync(dir)) {
|
||||
if (mkdirp === undefined) {
|
||||
try {mkdirp = require('mkdirp');}
|
||||
catch(e) { mkdirp = null; }
|
||||
}
|
||||
cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
cmd(dir);
|
||||
}
|
||||
};
|
||||
|
||||
if (options.lint) {
|
||||
options.sourceMap = false;
|
||||
}
|
||||
sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
|
||||
|
||||
if (options.sourceMap) {
|
||||
options.sourceMap = sourceMapOptions;
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
process.stdout.write(outputbase + ": ");
|
||||
}
|
||||
|
||||
less.logger.addListener({
|
||||
info: function(msg) {
|
||||
if (verbose) {
|
||||
if (!sourceMapFileInline) {
|
||||
var writeSourceMap = function(output, onDone) {
|
||||
var filename = sourceMapOptions.sourceMapFullFilename;
|
||||
ensureDirectory(filename);
|
||||
fs.writeFile(filename, output, 'utf8', function (err) {
|
||||
if (err) {
|
||||
var description = "Error: ";
|
||||
if (errno && errno.errno[err.errno]) {
|
||||
description += errno.errno[err.errno].description;
|
||||
} else {
|
||||
description += err.code + " " + err.message;
|
||||
}
|
||||
less.logger.error('lessc: failed to create file ' + filename);
|
||||
less.logger.error(description);
|
||||
} else {
|
||||
less.logger.info('lessc: wrote ' + filename);
|
||||
}
|
||||
onDone();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var writeSourceMapIfNeeded = function(output, onDone) {
|
||||
if (options.sourceMap && !sourceMapFileInline) {
|
||||
writeSourceMap(output, onDone);
|
||||
}
|
||||
};
|
||||
|
||||
var writeOutput = function(output, result, onSuccess) {
|
||||
if (output) {
|
||||
ensureDirectory(output);
|
||||
fs.writeFile(output, result.css, {encoding: 'utf8'}, function (err) {
|
||||
if (err) {
|
||||
var description = "Error: ";
|
||||
if (errno && errno.errno[err.errno]) {
|
||||
description += errno.errno[err.errno].description;
|
||||
} else {
|
||||
description += err.code + " " + err.message;
|
||||
}
|
||||
less.logger.error('lessc: failed to create file ' + output);
|
||||
less.logger.error(description);
|
||||
} else {
|
||||
less.logger.info('lessc: wrote ' + output);
|
||||
onSuccess();
|
||||
}
|
||||
});
|
||||
} else if (!options.depends) {
|
||||
process.stdout.write(result.css);
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
var logDependencies = function(options, result) {
|
||||
if (options.depends) {
|
||||
var depends = "";
|
||||
for(var i = 0; i < result.imports.length; i++) {
|
||||
depends += result.imports[i] + " ";
|
||||
}
|
||||
console.log(depends);
|
||||
}
|
||||
};
|
||||
|
||||
var parseLessFile = function (e, data) {
|
||||
if (e) {
|
||||
console.log("lessc: " + e.message);
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
data = data.replace(/^\uFEFF/, '');
|
||||
|
||||
options.paths = [path.dirname(input)].concat(options.paths);
|
||||
options.filename = input;
|
||||
|
||||
if (options.lint) {
|
||||
options.sourceMap = false;
|
||||
}
|
||||
sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
|
||||
|
||||
if (options.sourceMap) {
|
||||
options.sourceMap = sourceMapOptions;
|
||||
}
|
||||
|
||||
less.logger.addListener({
|
||||
info: function(msg) {
|
||||
if (verbose) {
|
||||
console.log(msg);
|
||||
}
|
||||
},
|
||||
warn: function(msg) {
|
||||
// do not show warning if outputting css to the console or the silent option is used
|
||||
if (!silent && output) {
|
||||
console.warn(msg);
|
||||
}
|
||||
},
|
||||
error: function(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
},
|
||||
warn: function(msg) {
|
||||
// do not show warning if outputting css to the console or the silent option is used
|
||||
if (!silent && output) {
|
||||
console.warn(msg);
|
||||
}
|
||||
},
|
||||
error: function(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
});
|
||||
|
||||
less.render(data, options)
|
||||
.then(function(result) {
|
||||
if(!options.lint) {
|
||||
if (output) {
|
||||
ensureDirectory(output);
|
||||
fs.writeFileSync(output, result.css, 'utf8');
|
||||
less.logger.info('lessc: wrote ' + output);
|
||||
} else if (!options.depends) {
|
||||
process.stdout.write(result.css);
|
||||
}
|
||||
if (options.sourceMap && !sourceMapFileInline) {
|
||||
writeSourceMap(result.map);
|
||||
}
|
||||
if (options.depends) {
|
||||
var depends = "";
|
||||
for(var i = 0; i < result.imports.length; i++) {
|
||||
depends += result.imports[i] + " ";
|
||||
}
|
||||
console.log(depends);
|
||||
}
|
||||
}
|
||||
},
|
||||
function(err) {
|
||||
less.writeError(err, options);
|
||||
currentErrorcode = 1;
|
||||
});
|
||||
};
|
||||
|
||||
if (input != '-') {
|
||||
fs.readFile(input, 'utf8', parseLessFile);
|
||||
} else {
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding('utf8');
|
||||
less.render(data, options)
|
||||
.then(function(result) {
|
||||
if(!options.lint) {
|
||||
writeOutput(output, result, function() {
|
||||
writeSourceMapIfNeeded(result.map, function() {
|
||||
logDependencies(options, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
function(err) {
|
||||
less.writeError(err, options);
|
||||
currentErrorcode = 1;
|
||||
});
|
||||
};
|
||||
|
||||
var buffer = '';
|
||||
process.stdin.on('data', function(data) {
|
||||
buffer += data;
|
||||
});
|
||||
if (input != '-') {
|
||||
fs.readFile(input, 'utf8', parseLessFile);
|
||||
} else {
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding('utf8');
|
||||
|
||||
process.stdin.on('end', function() {
|
||||
parseLessFile(false, buffer);
|
||||
});
|
||||
}
|
||||
var buffer = '';
|
||||
process.stdin.on('data', function(data) {
|
||||
buffer += data;
|
||||
});
|
||||
|
||||
process.stdin.on('end', function() {
|
||||
parseLessFile(false, buffer);
|
||||
});
|
||||
}
|
||||
})();
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "less",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"main": "dist/less.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
|
||||
378
dist/less.js
vendored
378
dist/less.js
vendored
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Less - Leaner CSS v2.2.0
|
||||
* Less - Leaner CSS v2.3.0
|
||||
* http://lesscss.org
|
||||
*
|
||||
* Copyright (c) 2009-2015, Alexis Sellier <self@cloudhead.net>
|
||||
@@ -52,9 +52,9 @@ module.exports = function(window, options) {
|
||||
options.useFileCache = true;
|
||||
}
|
||||
|
||||
if (options.onReady === undefined) {
|
||||
options.onReady = true;
|
||||
}
|
||||
if (options.onReady === undefined) {
|
||||
options.onReady = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -75,15 +75,15 @@ require("./add-default-options")(window, options);
|
||||
var less = module.exports = require("./index")(window, options);
|
||||
|
||||
if (options.onReady) {
|
||||
if (/!watch/.test(window.location.hash)) {
|
||||
less.watch();
|
||||
}
|
||||
|
||||
less.pageLoadFinished = less.registerStylesheets().then(
|
||||
function () {
|
||||
return less.refresh(less.env === 'development');
|
||||
}
|
||||
);
|
||||
if (/!watch/.test(window.location.hash)) {
|
||||
less.watch();
|
||||
}
|
||||
|
||||
less.pageLoadFinished = less.registerStylesheets().then(
|
||||
function () {
|
||||
return less.refresh(less.env === 'development');
|
||||
}
|
||||
);
|
||||
}
|
||||
},{"./add-default-options":1,"./index":7,"promise/polyfill.js":undefined}],3:[function(require,module,exports){
|
||||
var utils = require("./utils");
|
||||
@@ -596,14 +596,14 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
|
||||
if (webInfo) {
|
||||
webInfo.remaining = remaining;
|
||||
|
||||
if (!instanceOptions.modifyVars) {
|
||||
var css = cache.getCSS(path, webInfo);
|
||||
if (!reload && css) {
|
||||
webInfo.local = true;
|
||||
callback(null, null, data, sheet, webInfo, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!instanceOptions.modifyVars) {
|
||||
var css = cache.getCSS(path, webInfo);
|
||||
if (!reload && css) {
|
||||
webInfo.local = true;
|
||||
callback(null, css, data, sheet, webInfo, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO add tests around how this behaves when reloading
|
||||
@@ -615,11 +615,11 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
|
||||
e.href = path;
|
||||
callback(e);
|
||||
} else {
|
||||
result.css = postProcessCSS(result.css);
|
||||
if (!instanceOptions.modifyVars) {
|
||||
cache.setCSS(sheet.href, webInfo.lastModified, result.css);
|
||||
}
|
||||
callback(null, result.css, data, sheet, webInfo, path);
|
||||
result.css = postProcessCSS(result.css);
|
||||
if (!instanceOptions.modifyVars) {
|
||||
cache.setCSS(sheet.href, webInfo.lastModified, result.css);
|
||||
}
|
||||
callback(null, result.css, data, sheet, webInfo, path);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -716,7 +716,7 @@ less.refresh = function (reload, modifyVars, clearFileCache) {
|
||||
} else {
|
||||
less.logger.info("rendered " + sheet.href + " successfully.");
|
||||
}
|
||||
browser.createCSS(window.document, css, sheet);
|
||||
browser.createCSS(window.document, css, sheet);
|
||||
less.logger.info("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
|
||||
if (webInfo.remaining === 0) {
|
||||
totalMilliseconds = new Date() - startTime;
|
||||
@@ -854,6 +854,7 @@ contexts.Parse = function(options) {
|
||||
};
|
||||
|
||||
var evalCopyProperties = [
|
||||
'paths', // additional include paths
|
||||
'compress', // whether to compress
|
||||
'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
|
||||
'strictMath', // whether math has to be within parenthesis
|
||||
@@ -921,7 +922,6 @@ contexts.Eval.prototype.normalizePath = function( path ) {
|
||||
|
||||
//todo - do the same for the toCSS ?
|
||||
|
||||
|
||||
},{}],11:[function(require,module,exports){
|
||||
module.exports = {
|
||||
'aliceblue':'#f0f8ff',
|
||||
@@ -1613,7 +1613,7 @@ colorFunctions = {
|
||||
return new Color(c.value.slice(1));
|
||||
}
|
||||
if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) {
|
||||
c.keyword = undefined;
|
||||
c.value = undefined;
|
||||
return c;
|
||||
}
|
||||
throw {
|
||||
@@ -1649,8 +1649,9 @@ module.exports = function(environment) {
|
||||
|
||||
var mimetype = mimetypeNode && mimetypeNode.value;
|
||||
var filePath = filePathNode.value;
|
||||
var currentDirectory = filePathNode.currentFileInfo.relativeUrls ?
|
||||
filePathNode.currentFileInfo.currentDirectory : filePathNode.currentFileInfo.entryPath;
|
||||
var currentFileInfo = this.currentFileInfo;
|
||||
var currentDirectory = currentFileInfo.relativeUrls ?
|
||||
currentFileInfo.currentDirectory : currentFileInfo.entryPath;
|
||||
|
||||
var fragmentStart = filePath.indexOf('#');
|
||||
var fragment = '';
|
||||
@@ -1672,7 +1673,7 @@ module.exports = function(environment) {
|
||||
|
||||
mimetype = environment.mimeLookup(filePath);
|
||||
|
||||
if (mimetype === "image/svg+xml") {
|
||||
if (mimetype === "image/svg+xml") {
|
||||
useBase64 = false;
|
||||
} else {
|
||||
// use base 64 unless it's an ASCII or UTF-8 format
|
||||
@@ -1687,29 +1688,29 @@ module.exports = function(environment) {
|
||||
|
||||
var fileSync = fileManager.loadFileSync(filePath, currentDirectory, this.context, environment);
|
||||
if (!fileSync.contents) {
|
||||
logger.warn("Skipped data-uri embedding because file not found");
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because file not found");
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
var buf = fileSync.contents;
|
||||
if (useBase64 && !environment.encodeBase64) {
|
||||
return fallback(this, filePathNode);
|
||||
}
|
||||
if (useBase64 && !environment.encodeBase64) {
|
||||
return fallback(this, filePathNode);
|
||||
}
|
||||
|
||||
buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);
|
||||
|
||||
var uri = "data:" + mimetype + ',' + buf + fragment;
|
||||
|
||||
// IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
|
||||
// and the --ieCompat flag is enabled, return a normal url() instead.
|
||||
var DATA_URI_MAX = 32768;
|
||||
if (uri.length >= DATA_URI_MAX) {
|
||||
// IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
|
||||
// and the --ieCompat flag is enabled, return a normal url() instead.
|
||||
var DATA_URI_MAX = 32768;
|
||||
if (uri.length >= DATA_URI_MAX) {
|
||||
|
||||
if (this.context.ieCompat !== false) {
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length + " characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
|
||||
if (this.context.ieCompat !== false) {
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length + " characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
|
||||
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
}
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
}
|
||||
|
||||
return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
|
||||
});
|
||||
@@ -1964,6 +1965,7 @@ functionRegistry.addMultiple({
|
||||
module.exports = function(environment) {
|
||||
var Dimension = require("../tree/dimension"),
|
||||
Color = require("../tree/color"),
|
||||
Expression = require("../tree/expression"),
|
||||
Quoted = require("../tree/quoted"),
|
||||
URL = require("../tree/url"),
|
||||
functionRegistry = require("./function-registry");
|
||||
@@ -2013,7 +2015,7 @@ module.exports = function(environment) {
|
||||
'<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
|
||||
|
||||
for (i = 0; i < stops.length; i+= 1) {
|
||||
if (stops[i].value) {
|
||||
if (stops[i] instanceof Expression) {
|
||||
color = stops[i].value[0];
|
||||
position = stops[i].value[1];
|
||||
} else {
|
||||
@@ -2038,8 +2040,9 @@ module.exports = function(environment) {
|
||||
});
|
||||
};
|
||||
|
||||
},{"../tree/color":47,"../tree/dimension":53,"../tree/quoted":70,"../tree/url":77,"./function-registry":21}],27:[function(require,module,exports){
|
||||
},{"../tree/color":47,"../tree/dimension":53,"../tree/expression":56,"../tree/quoted":70,"../tree/url":77,"./function-registry":21}],27:[function(require,module,exports){
|
||||
var Keyword = require("../tree/keyword"),
|
||||
DetachedRuleset = require("../tree/detached-ruleset"),
|
||||
Dimension = require("../tree/dimension"),
|
||||
Color = require("../tree/color"),
|
||||
Quoted = require("../tree/quoted"),
|
||||
@@ -2062,6 +2065,9 @@ var isa = function (n, Type) {
|
||||
return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;
|
||||
};
|
||||
functionRegistry.addMultiple({
|
||||
isruleset: function (n) {
|
||||
return isa(n, DetachedRuleset);
|
||||
},
|
||||
iscolor: function (n) {
|
||||
return isa(n, Color);
|
||||
},
|
||||
@@ -2118,7 +2124,7 @@ functionRegistry.addMultiple({
|
||||
}
|
||||
});
|
||||
|
||||
},{"../tree/anonymous":43,"../tree/color":47,"../tree/dimension":53,"../tree/keyword":62,"../tree/operation":68,"../tree/quoted":70,"../tree/url":77,"./function-registry":21}],28:[function(require,module,exports){
|
||||
},{"../tree/anonymous":43,"../tree/color":47,"../tree/detached-ruleset":52,"../tree/dimension":53,"../tree/keyword":62,"../tree/operation":68,"../tree/quoted":70,"../tree/url":77,"./function-registry":21}],28:[function(require,module,exports){
|
||||
var contexts = require("./contexts"),
|
||||
Parser = require('./parser/parser');
|
||||
|
||||
@@ -2161,12 +2167,14 @@ module.exports = function(environment) {
|
||||
importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue
|
||||
|
||||
var importedEqualsRoot = fullPath === importManager.rootFilename;
|
||||
|
||||
if (importOptions.optional && e) {
|
||||
callback(null, {rules:[]}, false, null);
|
||||
}
|
||||
else {
|
||||
importManager.files[fullPath] = root;
|
||||
|
||||
if (e && !importManager.error) { importManager.error = e; }
|
||||
|
||||
callback(e, root, importedEqualsRoot, fullPath);
|
||||
}
|
||||
};
|
||||
|
||||
var newFileInfo = {
|
||||
@@ -2189,7 +2197,7 @@ module.exports = function(environment) {
|
||||
|
||||
var loadFileCallback = function(loadedFile) {
|
||||
var resolvedFilename = loadedFile.filename,
|
||||
contents = loadedFile.contents;
|
||||
contents = loadedFile.contents.replace(/^\uFEFF/, '');
|
||||
|
||||
// Pass on an updated rootpath if path of imported file is relative and file
|
||||
// is in a (sub|sup) directory
|
||||
@@ -2246,7 +2254,7 @@ module.exports = function(environment, fileManagers) {
|
||||
var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
|
||||
|
||||
var less = {
|
||||
version: [2, 2, 0],
|
||||
version: [2, 3, 0],
|
||||
data: require('./data'),
|
||||
tree: require('./tree'),
|
||||
Environment: (Environment = require("./environment/environment")),
|
||||
@@ -2355,7 +2363,7 @@ module.exports = {
|
||||
},{}],32:[function(require,module,exports){
|
||||
var LessError = require('./less-error'),
|
||||
transformTree = require("./transform-tree"),
|
||||
logger = require("./logger");
|
||||
logger = require("./logger");
|
||||
|
||||
module.exports = function(SourceMapBuilder) {
|
||||
var ParseTree = function(root, imports) {
|
||||
@@ -2372,11 +2380,11 @@ ParseTree.prototype.toCSS = function(options) {
|
||||
}
|
||||
|
||||
try {
|
||||
var compress = Boolean(options.compress);
|
||||
if (compress) {
|
||||
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
|
||||
}
|
||||
|
||||
var compress = Boolean(options.compress);
|
||||
if (compress) {
|
||||
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
|
||||
}
|
||||
|
||||
var toCSSOptions = {
|
||||
compress: compress,
|
||||
dumpLineNumbers: options.dumpLineNumbers,
|
||||
@@ -2463,6 +2471,10 @@ module.exports = function(environment, ParseTree, ImportManager) {
|
||||
entryPath: entryPath,
|
||||
rootFilename: filename
|
||||
};
|
||||
// add in a missing trailing slash
|
||||
if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== "/") {
|
||||
rootFileInfo.rootpath += "/";
|
||||
}
|
||||
}
|
||||
|
||||
var imports = new ImportManager(context, rootFileInfo);
|
||||
@@ -3085,13 +3097,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
primary: function () {
|
||||
var mixin = this.mixin, root = [], node;
|
||||
|
||||
while (!parserInput.finished)
|
||||
while (true)
|
||||
{
|
||||
while(true) {
|
||||
node = this.comment();
|
||||
if (!node) { break; }
|
||||
root.push(node);
|
||||
}
|
||||
// always process comments before deciding if finished
|
||||
if (parserInput.finished) {
|
||||
break;
|
||||
}
|
||||
if (parserInput.peek('}')) {
|
||||
break;
|
||||
}
|
||||
@@ -3712,7 +3728,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
c = this.combinator();
|
||||
|
||||
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
||||
parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^()@]+\)/) || parserInput.$re(/^[\.#](?=@)/) ||
|
||||
parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
|
||||
this.entities.variableCurly();
|
||||
|
||||
if (! e) {
|
||||
@@ -4023,7 +4039,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
},
|
||||
|
||||
importOption: function() {
|
||||
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference)/);
|
||||
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
|
||||
if (opt) {
|
||||
return opt[1];
|
||||
}
|
||||
@@ -4237,19 +4253,19 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
sub: function () {
|
||||
var a, e;
|
||||
|
||||
parserInput.save();
|
||||
parserInput.save();
|
||||
if (parserInput.$char('(')) {
|
||||
a = this.addition();
|
||||
if (a && parserInput.$char(')')) {
|
||||
parserInput.forget();
|
||||
e = new(tree.Expression)([a]);
|
||||
e.parens = true;
|
||||
parserInput.forget();
|
||||
e = new(tree.Expression)([a]);
|
||||
e.parens = true;
|
||||
return e;
|
||||
}
|
||||
parserInput.restore("Expected ')'");
|
||||
return;
|
||||
parserInput.restore("Expected ')'");
|
||||
return;
|
||||
}
|
||||
parserInput.restore();
|
||||
parserInput.restore();
|
||||
},
|
||||
multiplication: function () {
|
||||
var m, a, op, operation, isSpaced;
|
||||
@@ -4963,7 +4979,6 @@ Assignment.prototype.genCSS = function (context, output) {
|
||||
};
|
||||
module.exports = Assignment;
|
||||
|
||||
|
||||
},{"./node":67}],45:[function(require,module,exports){
|
||||
var Node = require("./node");
|
||||
|
||||
@@ -5116,11 +5131,11 @@ Color.prototype.genCSS = function (context, output) {
|
||||
Color.prototype.toCSS = function (context, doNotCompress) {
|
||||
var compress = context && context.compress && !doNotCompress, color, alpha;
|
||||
|
||||
// `keyword` is set if this color was originally
|
||||
// `value` is set if this color was originally
|
||||
// converted from a named color string so we need
|
||||
// to respect this and try to output named color too.
|
||||
if (this.keyword) {
|
||||
return this.keyword;
|
||||
if (this.value) {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
// If we have some transparency, the only way to represent it
|
||||
@@ -5239,7 +5254,7 @@ Color.fromKeyword = function(keyword) {
|
||||
}
|
||||
|
||||
if (c) {
|
||||
c.keyword = keyword;
|
||||
c.value = keyword;
|
||||
return c;
|
||||
}
|
||||
};
|
||||
@@ -5555,7 +5570,7 @@ module.exports = Dimension;
|
||||
var Node = require("./node"),
|
||||
Ruleset = require("./ruleset");
|
||||
|
||||
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo) {
|
||||
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isReferenced) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
if (rules) {
|
||||
@@ -5565,6 +5580,7 @@ var Directive = function (name, value, rules, index, currentFileInfo, debugInfo)
|
||||
this.index = index;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
this.debugInfo = debugInfo;
|
||||
this.isReferenced = isReferenced;
|
||||
};
|
||||
|
||||
Directive.prototype = new Node();
|
||||
@@ -5592,7 +5608,10 @@ Directive.prototype.genCSS = function (context, output) {
|
||||
value.genCSS(context, output);
|
||||
}
|
||||
if (rules) {
|
||||
this.outputRuleset(context, output, [rules]);
|
||||
if (rules.type === "Ruleset") {
|
||||
rules = [rules];
|
||||
}
|
||||
this.outputRuleset(context, output, rules);
|
||||
} else {
|
||||
output.add(';');
|
||||
}
|
||||
@@ -5607,7 +5626,7 @@ Directive.prototype.eval = function (context) {
|
||||
rules.root = true;
|
||||
}
|
||||
return new Directive(this.name, value, rules,
|
||||
this.index, this.currentFileInfo, this.debugInfo);
|
||||
this.index, this.currentFileInfo, this.debugInfo, this.isReferenced);
|
||||
};
|
||||
Directive.prototype.variable = function (name) { if (this.rules) return Ruleset.prototype.variable.call(this.rules, name); };
|
||||
Directive.prototype.find = function () { if (this.rules) return Ruleset.prototype.find.apply(this.rules, arguments); };
|
||||
@@ -5624,6 +5643,9 @@ Directive.prototype.markReferenced = function () {
|
||||
}
|
||||
}
|
||||
};
|
||||
Directive.prototype.getIsReferenced = function () {
|
||||
return !this.currentFileInfo || !this.currentFileInfo.reference || this.isReferenced;
|
||||
};
|
||||
Directive.prototype.outputRuleset = function (context, output, rules) {
|
||||
var ruleCnt = rules.length, i;
|
||||
context.tabLevel = (context.tabLevel | 0) + 1;
|
||||
@@ -5720,7 +5742,7 @@ var Node = require("./node"),
|
||||
var Expression = function (value) {
|
||||
this.value = value;
|
||||
if (!value) {
|
||||
throw new Error("Expression requires a array parameter");
|
||||
throw new Error("Expression requires an array parameter");
|
||||
}
|
||||
};
|
||||
Expression.prototype = new Node();
|
||||
@@ -5968,6 +5990,7 @@ module.exports = Import;
|
||||
},{"./anonymous":43,"./media":63,"./node":67,"./quoted":70,"./ruleset":73,"./url":77}],59:[function(require,module,exports){
|
||||
var tree = {};
|
||||
|
||||
tree.Node = require('./node');
|
||||
tree.Alpha = require('./alpha');
|
||||
tree.Color = require('./color');
|
||||
tree.Directive = require('./directive');
|
||||
@@ -6007,7 +6030,7 @@ tree.RulesetCall = require('./ruleset-call');
|
||||
|
||||
module.exports = tree;
|
||||
|
||||
},{"./alpha":42,"./anonymous":43,"./assignment":44,"./attribute":45,"./call":46,"./color":47,"./combinator":48,"./comment":49,"./condition":50,"./detached-ruleset":52,"./dimension":53,"./directive":54,"./element":55,"./expression":56,"./extend":57,"./import":58,"./javascript":60,"./keyword":62,"./media":63,"./mixin-call":64,"./mixin-definition":65,"./negative":66,"./operation":68,"./paren":69,"./quoted":70,"./rule":71,"./ruleset":73,"./ruleset-call":72,"./selector":74,"./unicode-descriptor":75,"./unit":76,"./url":77,"./value":78,"./variable":79}],60:[function(require,module,exports){
|
||||
},{"./alpha":42,"./anonymous":43,"./assignment":44,"./attribute":45,"./call":46,"./color":47,"./combinator":48,"./comment":49,"./condition":50,"./detached-ruleset":52,"./dimension":53,"./directive":54,"./element":55,"./expression":56,"./extend":57,"./import":58,"./javascript":60,"./keyword":62,"./media":63,"./mixin-call":64,"./mixin-definition":65,"./negative":66,"./node":67,"./operation":68,"./paren":69,"./quoted":70,"./rule":71,"./ruleset":73,"./ruleset-call":72,"./selector":74,"./unicode-descriptor":75,"./unit":76,"./url":77,"./value":78,"./variable":79}],60:[function(require,module,exports){
|
||||
var JsEvalNode = require("./js-eval-node"),
|
||||
Dimension = require("./dimension"),
|
||||
Quoted = require("./quoted"),
|
||||
@@ -7137,15 +7160,15 @@ Ruleset.prototype.evalImports = function(context) {
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.makeImportant = function() {
|
||||
return new Ruleset(this.selectors, this.rules.map(function (r) {
|
||||
if (r.makeImportant) {
|
||||
return r.makeImportant();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}), this.strictImports);
|
||||
};
|
||||
Ruleset.prototype.matchArgs = function (args) {
|
||||
this.rules = this.rules.map(function (r) {
|
||||
if (r.makeImportant) {
|
||||
return r.makeImportant();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};Ruleset.prototype.matchArgs = function (args) {
|
||||
return !args || args.length === 0;
|
||||
};
|
||||
// lets you call a css selector with a guard
|
||||
@@ -7175,7 +7198,7 @@ Ruleset.prototype.variables = function () {
|
||||
}
|
||||
// when evaluating variables in an import statement, imports have not been eval'd
|
||||
// so we need to go inside import statements.
|
||||
// guard against root being a string (in the case of inlined less)
|
||||
// guard against root being a string (in the case of inlined less)
|
||||
if (r.type === "Import" && r.root && r.root.variables) {
|
||||
var vars = r.root.variables();
|
||||
for(var name in vars) {
|
||||
@@ -7369,18 +7392,49 @@ Ruleset.prototype.genCSS = function (context, output) {
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.markReferenced = function () {
|
||||
if (!this.selectors) {
|
||||
return;
|
||||
var s;
|
||||
if (this.selectors) {
|
||||
for (s = 0; s < this.selectors.length; s++) {
|
||||
this.selectors[s].markReferenced();
|
||||
}
|
||||
}
|
||||
for (var s = 0; s < this.selectors.length; s++) {
|
||||
this.selectors[s].markReferenced();
|
||||
|
||||
if (this.rules) {
|
||||
for (s = 0; s < this.rules.length; s++) {
|
||||
if (this.rules[s].markReferenced)
|
||||
this.rules[s].markReferenced();
|
||||
}
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.getIsReferenced = function() {
|
||||
var i, j, path, selector;
|
||||
|
||||
if (this.paths) {
|
||||
for (i=0; i<this.paths.length; i++) {
|
||||
path = this.paths[i];
|
||||
for (j=0; j<path.length; j++) {
|
||||
if (path[j].getIsReferenced && path[j].getIsReferenced())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectors) {
|
||||
for (i=0;i<this.selectors.length;i++) {
|
||||
selector = this.selectors[i];
|
||||
if (selector.getIsReferenced && selector.getIsReferenced())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
|
||||
for (var s = 0; s < selectors.length; s++) {
|
||||
this.joinSelector(paths, context, selectors[s]);
|
||||
}
|
||||
};
|
||||
|
||||
Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
|
||||
var i, j, k,
|
||||
@@ -7968,7 +8022,8 @@ module.exports = {
|
||||
|
||||
},{}],81:[function(require,module,exports){
|
||||
var tree = require("../tree"),
|
||||
Visitor = require("./visitor");
|
||||
Visitor = require("./visitor"),
|
||||
logger = require("../logger");
|
||||
|
||||
/*jshint loopfunc:true */
|
||||
|
||||
@@ -8063,11 +8118,30 @@ var ProcessExtendsVisitor = function() {
|
||||
ProcessExtendsVisitor.prototype = {
|
||||
run: function(root) {
|
||||
var extendFinder = new ExtendFinderVisitor();
|
||||
this.extendIndicies = {};
|
||||
extendFinder.run(root);
|
||||
if (!extendFinder.foundExtends) { return root; }
|
||||
root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
|
||||
this.allExtendsStack = [root.allExtends];
|
||||
return this._visitor.visit(root);
|
||||
var newRoot = this._visitor.visit(root);
|
||||
this.checkExtendsForNonMatched(root.allExtends);
|
||||
return newRoot;
|
||||
},
|
||||
checkExtendsForNonMatched: function(extendList) {
|
||||
var indicies = this.extendIndicies;
|
||||
extendList.filter(function(extend) {
|
||||
return !extend.hasFoundMatches && extend.parent_ids.length == 1;
|
||||
}).forEach(function(extend) {
|
||||
var selector = "_unknown_";
|
||||
try {
|
||||
selector = extend.selector.toCSS({});
|
||||
}catch(_){}
|
||||
|
||||
if(!indicies[extend.index + ' ' + selector]) {
|
||||
indicies[extend.index + ' ' + selector] = true;
|
||||
logger.warn("extend '"+selector+"' has no matches");
|
||||
}
|
||||
});
|
||||
},
|
||||
doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
|
||||
//
|
||||
@@ -8104,6 +8178,8 @@ ProcessExtendsVisitor.prototype = {
|
||||
|
||||
if (matches.length) {
|
||||
|
||||
extend.hasFoundMatches = true;
|
||||
|
||||
// we found a match, so for each self selector..
|
||||
extend.selfSelectors.forEach(function(selfSelector) {
|
||||
|
||||
@@ -8187,6 +8263,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
matches = this.findMatch(allExtends[extendIndex], selectorPath);
|
||||
|
||||
if (matches.length) {
|
||||
allExtends[extendIndex].hasFoundMatches = true;
|
||||
|
||||
allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
|
||||
selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
|
||||
@@ -8372,7 +8449,9 @@ ProcessExtendsVisitor.prototype = {
|
||||
this.allExtendsStack.push(newAllExtends);
|
||||
},
|
||||
visitMediaOut: function (mediaNode) {
|
||||
this.allExtendsStack.length = this.allExtendsStack.length - 1;
|
||||
var lastIndex = this.allExtendsStack.length - 1;
|
||||
this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
|
||||
this.allExtendsStack.length = lastIndex;
|
||||
},
|
||||
visitDirective: function (directiveNode, visitArgs) {
|
||||
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
|
||||
@@ -8380,18 +8459,20 @@ ProcessExtendsVisitor.prototype = {
|
||||
this.allExtendsStack.push(newAllExtends);
|
||||
},
|
||||
visitDirectiveOut: function (directiveNode) {
|
||||
this.allExtendsStack.length = this.allExtendsStack.length - 1;
|
||||
var lastIndex = this.allExtendsStack.length - 1;
|
||||
this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
|
||||
this.allExtendsStack.length = lastIndex;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ProcessExtendsVisitor;
|
||||
|
||||
},{"../tree":59,"./visitor":87}],82:[function(require,module,exports){
|
||||
},{"../logger":31,"../tree":59,"./visitor":87}],82:[function(require,module,exports){
|
||||
function ImportSequencer(onSequencerEmpty) {
|
||||
this.imports = [];
|
||||
this.variableImports = [];
|
||||
this._onSequencerEmpty = onSequencerEmpty;
|
||||
this._currentDepth = 0;
|
||||
this._currentDepth = 0;
|
||||
}
|
||||
|
||||
ImportSequencer.prototype.addImport = function(callback) {
|
||||
@@ -8414,27 +8495,27 @@ ImportSequencer.prototype.addVariableImport = function(callback) {
|
||||
};
|
||||
|
||||
ImportSequencer.prototype.tryRun = function() {
|
||||
this._currentDepth++;
|
||||
try {
|
||||
while(true) {
|
||||
while(this.imports.length > 0) {
|
||||
var importItem = this.imports[0];
|
||||
if (!importItem.isReady) {
|
||||
return;
|
||||
}
|
||||
this.imports = this.imports.slice(1);
|
||||
importItem.callback.apply(null, importItem.args);
|
||||
}
|
||||
if (this.variableImports.length === 0) {
|
||||
break;
|
||||
}
|
||||
var variableImport = this.variableImports[0];
|
||||
this.variableImports = this.variableImports.slice(1);
|
||||
variableImport();
|
||||
}
|
||||
} finally {
|
||||
this._currentDepth--;
|
||||
}
|
||||
this._currentDepth++;
|
||||
try {
|
||||
while(true) {
|
||||
while(this.imports.length > 0) {
|
||||
var importItem = this.imports[0];
|
||||
if (!importItem.isReady) {
|
||||
return;
|
||||
}
|
||||
this.imports = this.imports.slice(1);
|
||||
importItem.callback.apply(null, importItem.args);
|
||||
}
|
||||
if (this.variableImports.length === 0) {
|
||||
break;
|
||||
}
|
||||
var variableImport = this.variableImports[0];
|
||||
this.variableImports = this.variableImports.slice(1);
|
||||
variableImport();
|
||||
}
|
||||
} finally {
|
||||
this._currentDepth--;
|
||||
}
|
||||
if (this._currentDepth === 0 && this._onSequencerEmpty) {
|
||||
this._onSequencerEmpty();
|
||||
}
|
||||
@@ -8473,12 +8554,12 @@ ImportVisitor.prototype = {
|
||||
this.isFinished = true;
|
||||
this._sequencer.tryRun();
|
||||
},
|
||||
_onSequencerEmpty: function() {
|
||||
if (!this.isFinished) {
|
||||
return;
|
||||
}
|
||||
this._finish(this.error);
|
||||
},
|
||||
_onSequencerEmpty: function() {
|
||||
if (!this.isFinished) {
|
||||
return;
|
||||
}
|
||||
this._finish(this.error);
|
||||
},
|
||||
visitImport: function (importNode, visitArgs) {
|
||||
var inlineCSS = importNode.options.inline;
|
||||
|
||||
@@ -8532,9 +8613,9 @@ ImportVisitor.prototype = {
|
||||
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo, evaldImportNode.options, sequencedOnImported);
|
||||
} else {
|
||||
this.importCount--;
|
||||
if (this.isFinished) {
|
||||
this._sequencer.tryRun();
|
||||
}
|
||||
if (this.isFinished) {
|
||||
this._sequencer.tryRun();
|
||||
}
|
||||
}
|
||||
},
|
||||
onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
|
||||
@@ -8584,7 +8665,7 @@ ImportVisitor.prototype = {
|
||||
importVisitor.importCount--;
|
||||
|
||||
if (importVisitor.isFinished) {
|
||||
importVisitor._sequencer.tryRun();
|
||||
importVisitor._sequencer.tryRun();
|
||||
}
|
||||
},
|
||||
visitRule: function (ruleNode, visitArgs) {
|
||||
@@ -8724,10 +8805,10 @@ ToCSSVisitor.prototype = {
|
||||
},
|
||||
|
||||
visitDirective: function(directiveNode, visitArgs) {
|
||||
if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
|
||||
return;
|
||||
}
|
||||
if (directiveNode.name === "@charset") {
|
||||
if (!directiveNode.getIsReferenced()) {
|
||||
return;
|
||||
}
|
||||
// Only output the debug info together with subsequent @charset definitions
|
||||
// a comment (or @media statement) before the actual @charset directive would
|
||||
// be considered illegal css as it has to be on the first line
|
||||
@@ -8743,6 +8824,37 @@ ToCSSVisitor.prototype = {
|
||||
}
|
||||
if (directiveNode.rules && directiveNode.rules.rules) {
|
||||
this._mergeRules(directiveNode.rules.rules);
|
||||
//process childs
|
||||
directiveNode.accept(this._visitor);
|
||||
visitArgs.visitDeeper = false;
|
||||
|
||||
// the directive was directly referenced and therefore needs to be shown in the output
|
||||
if (directiveNode.getIsReferenced()) {
|
||||
return directiveNode;
|
||||
}
|
||||
|
||||
if (!directiveNode.rules.rules) {
|
||||
return ;
|
||||
}
|
||||
|
||||
//the directive was not directly referenced
|
||||
for (var r = 0; r<directiveNode.rules.rules.length; r++) {
|
||||
var rule = directiveNode.rules.rules[r];
|
||||
if (rule.getIsReferenced && rule.getIsReferenced()) {
|
||||
//the directive contains something that was referenced (likely by extend)
|
||||
//therefore it needs to be shown in output too
|
||||
|
||||
//marking as referenced in case the directive is stored inside another directive
|
||||
directiveNode.markReferenced();
|
||||
return directiveNode;
|
||||
}
|
||||
}
|
||||
//The directive was not directly referenced and does not contain anything that
|
||||
//was referenced. Therefore it must not be shown in output.
|
||||
return ;
|
||||
} else {
|
||||
if (!directiveNode.getIsReferenced())
|
||||
return;
|
||||
}
|
||||
return directiveNode;
|
||||
},
|
||||
|
||||
12
dist/less.min.js
vendored
12
dist/less.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -39,8 +39,8 @@ module.exports = function(window, options) {
|
||||
options.useFileCache = true;
|
||||
}
|
||||
|
||||
if (options.onReady === undefined) {
|
||||
options.onReady = true;
|
||||
}
|
||||
if (options.onReady === undefined) {
|
||||
options.onReady = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
18
lib/less-browser/bootstrap.js
vendored
18
lib/less-browser/bootstrap.js
vendored
@@ -14,13 +14,13 @@ require("./add-default-options")(window, options);
|
||||
var less = module.exports = require("./index")(window, options);
|
||||
|
||||
if (options.onReady) {
|
||||
if (/!watch/.test(window.location.hash)) {
|
||||
less.watch();
|
||||
}
|
||||
|
||||
less.pageLoadFinished = less.registerStylesheets().then(
|
||||
function () {
|
||||
return less.refresh(less.env === 'development');
|
||||
}
|
||||
);
|
||||
if (/!watch/.test(window.location.hash)) {
|
||||
less.watch();
|
||||
}
|
||||
|
||||
less.pageLoadFinished = less.registerStylesheets().then(
|
||||
function () {
|
||||
return less.refresh(less.env === 'development');
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -112,14 +112,14 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
|
||||
if (webInfo) {
|
||||
webInfo.remaining = remaining;
|
||||
|
||||
if (!instanceOptions.modifyVars) {
|
||||
var css = cache.getCSS(path, webInfo);
|
||||
if (!reload && css) {
|
||||
webInfo.local = true;
|
||||
callback(null, css, data, sheet, webInfo, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!instanceOptions.modifyVars) {
|
||||
var css = cache.getCSS(path, webInfo);
|
||||
if (!reload && css) {
|
||||
webInfo.local = true;
|
||||
callback(null, css, data, sheet, webInfo, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO add tests around how this behaves when reloading
|
||||
@@ -131,11 +131,11 @@ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
|
||||
e.href = path;
|
||||
callback(e);
|
||||
} else {
|
||||
result.css = postProcessCSS(result.css);
|
||||
if (!instanceOptions.modifyVars) {
|
||||
cache.setCSS(sheet.href, webInfo.lastModified, result.css);
|
||||
}
|
||||
callback(null, result.css, data, sheet, webInfo, path);
|
||||
result.css = postProcessCSS(result.css);
|
||||
if (!instanceOptions.modifyVars) {
|
||||
cache.setCSS(sheet.href, webInfo.lastModified, result.css);
|
||||
}
|
||||
callback(null, result.css, data, sheet, webInfo, path);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -232,7 +232,7 @@ less.refresh = function (reload, modifyVars, clearFileCache) {
|
||||
} else {
|
||||
less.logger.info("rendered " + sheet.href + " successfully.");
|
||||
}
|
||||
browser.createCSS(window.document, css, sheet);
|
||||
browser.createCSS(window.document, css, sheet);
|
||||
less.logger.info("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
|
||||
if (webInfo.remaining === 0) {
|
||||
totalMilliseconds = new Date() - startTime;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
extractId: function(href) {
|
||||
return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
|
||||
.replace(/[\?\&]livereload=\w+/,'' ) // Remove LiveReload cachebuster
|
||||
.replace(/^\//, '' ) // Remove root /
|
||||
.replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
|
||||
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
|
||||
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
|
||||
.replace(/[\?\&]livereload=\w+/, '' ) // Remove LiveReload cachebuster
|
||||
.replace(/^\//, '' ) // Remove root /
|
||||
.replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
|
||||
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
|
||||
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
|
||||
},
|
||||
addDataAttr: function(options, tag) {
|
||||
for (var opt in tag.dataset) {
|
||||
|
||||
@@ -30,7 +30,7 @@ FileManager.prototype.loadFile = function(filename, currentDirectory, options, e
|
||||
}
|
||||
|
||||
var paths = isAbsoluteFilename ? [""] : [currentDirectory];
|
||||
if (options.paths) paths.push.apply(paths, options.paths);
|
||||
if (options.paths) { paths.push.apply(paths, options.paths); }
|
||||
if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
|
||||
|
||||
// promise is guarenteed to be asyncronous
|
||||
@@ -39,10 +39,10 @@ FileManager.prototype.loadFile = function(filename, currentDirectory, options, e
|
||||
return new PromiseConstructor(function(fulfill, reject) {
|
||||
(function tryPathIndex(i) {
|
||||
if (i < paths.length) {
|
||||
fullFilename = filename;
|
||||
if (paths[i]) {
|
||||
fullFilename = filename;
|
||||
if (paths[i]) {
|
||||
fullFilename = path.join(paths[i], fullFilename);
|
||||
}
|
||||
}
|
||||
fs.stat(fullFilename, function (err) {
|
||||
if (err) {
|
||||
filenamesTried.push(fullFilename);
|
||||
@@ -63,12 +63,16 @@ FileManager.prototype.loadFile = function(filename, currentDirectory, options, e
|
||||
};
|
||||
|
||||
FileManager.prototype.loadFileSync = function(filename, currentDirectory, options, environment, encoding) {
|
||||
var fullFilename, paths, filenamesTried=[], isAbsoluteFilename = this.isPathAbsolute(filename),data;
|
||||
var fullFilename, paths, filenamesTried = [], isAbsoluteFilename = this.isPathAbsolute(filename) , data;
|
||||
options = options || {};
|
||||
|
||||
paths = isAbsoluteFilename ? [""] : [currentDirectory];
|
||||
if (options.paths) paths.push.apply(paths, options.paths);
|
||||
if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
|
||||
if (options.paths) {
|
||||
paths.push.apply(paths, options.paths);
|
||||
}
|
||||
if (!isAbsoluteFilename && paths.indexOf('.') === -1) {
|
||||
paths.push('.');
|
||||
}
|
||||
|
||||
var err, result;
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
var Dimension = require("../less/tree/dimension"),
|
||||
Expression = require("../less/tree/expression"),
|
||||
functionRegistry = require("./../less/functions/function-registry"),
|
||||
path = require("path");
|
||||
Expression = require("../less/tree/expression"),
|
||||
functionRegistry = require("./../less/functions/function-registry"),
|
||||
path = require("path");
|
||||
|
||||
function imageSize(filePathNode) {
|
||||
var filePath = filePathNode.value;
|
||||
var currentDirectory = filePathNode.currentFileInfo.relativeUrls ?
|
||||
filePathNode.currentFileInfo.currentDirectory : filePathNode.currentFileInfo.entryPath;
|
||||
var filePath = filePathNode.value;
|
||||
var currentDirectory = filePathNode.currentFileInfo.relativeUrls ?
|
||||
filePathNode.currentFileInfo.currentDirectory : filePathNode.currentFileInfo.entryPath;
|
||||
|
||||
var sizeOf = require('image-size');
|
||||
filePath = path.join(currentDirectory, filePath);
|
||||
return sizeOf(filePath);
|
||||
var sizeOf = require('image-size');
|
||||
filePath = path.join(currentDirectory, filePath);
|
||||
return sizeOf(filePath);
|
||||
}
|
||||
|
||||
var imageFunctions = {
|
||||
"image-size": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Expression([
|
||||
new Dimension(size.width, "px"),
|
||||
new Dimension(size.height, "px")
|
||||
]);
|
||||
},
|
||||
"image-width": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Dimension(size.width, "px");
|
||||
},
|
||||
"image-height": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Dimension(size.height, "px");
|
||||
}
|
||||
"image-size": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Expression([
|
||||
new Dimension(size.width, "px"),
|
||||
new Dimension(size.height, "px")
|
||||
]);
|
||||
},
|
||||
"image-width": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Dimension(size.width, "px");
|
||||
},
|
||||
"image-height": function(filePathNode) {
|
||||
var size = imageSize(filePathNode);
|
||||
return new Dimension(size.height, "px");
|
||||
}
|
||||
};
|
||||
|
||||
functionRegistry.addMultiple(imageFunctions);
|
||||
@@ -41,7 +41,7 @@ var lessc_helper = {
|
||||
console.log(" --source-map-rootpath=X Adds this path onto the sourcemap filename and less file paths.");
|
||||
console.log(" --source-map-basepath=X Sets sourcemap base path, defaults to current working directory.");
|
||||
console.log(" --source-map-less-inline Puts the less files into the map instead of referencing them.");
|
||||
console.log(" --source-map-map-inline Puts the map (and any less files) into the output css file.");
|
||||
console.log(" --source-map-map-inline Puts the map (and any less files) as a base64 data uri into the output css file.");
|
||||
console.log(" --source-map-url=URL Sets a custom URL to map file, for sourceMappingURL comment");
|
||||
console.log(" in generated CSS file.");
|
||||
console.log(" -rp, --rootpath=URL Sets rootpath for url rewriting in relative imports and urls");
|
||||
@@ -70,8 +70,8 @@ var lessc_helper = {
|
||||
console.log(" media query which is compatible with the SASS");
|
||||
console.log(" format, and 'all' which will do both.");
|
||||
console.log(" --verbose Be verbose.");
|
||||
console.log(" -x, --compress Compresses output by removing some whitespaces.");
|
||||
console.log(" We recommend you use a dedicated minifer like less-plugin-clean-css");
|
||||
console.log(" -x, --compress Compresses output by removing some whitespaces.");
|
||||
console.log(" We recommend you use a dedicated minifer like less-plugin-clean-css");
|
||||
console.log("");
|
||||
console.log("Report bugs to: http://github.com/less/less.js/issues");
|
||||
console.log("Home page: <http://lesscss.org/>");
|
||||
|
||||
@@ -35,7 +35,7 @@ UrlFileManager.prototype.loadFile = function(filename, currentDirectory, options
|
||||
|
||||
request.get({uri: urlStr, strictSSL: !options.insecure }, function (error, res, body) {
|
||||
if (error) {
|
||||
reject({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" });
|
||||
reject({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n " + error + "\n" });
|
||||
return;
|
||||
}
|
||||
if (res && res.statusCode === 404) {
|
||||
@@ -43,7 +43,7 @@ UrlFileManager.prototype.loadFile = function(filename, currentDirectory, options
|
||||
return;
|
||||
}
|
||||
if (!body) {
|
||||
logger.warn('Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"');
|
||||
logger.warn('Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr + '"');
|
||||
}
|
||||
fulfill({ contents: body, filename: urlStr });
|
||||
});
|
||||
|
||||
@@ -114,7 +114,7 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
var relativeSubDirectory = file.slice(0, j + 1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
@@ -135,7 +135,6 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
@@ -178,7 +177,7 @@ function writeFile(filename, content) {
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
print(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
@@ -371,7 +370,6 @@ function writeFile(filename, content) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
|
||||
@@ -108,4 +108,3 @@ contexts.Eval.prototype.normalizePath = function( path ) {
|
||||
};
|
||||
|
||||
//todo - do the same for the toCSS ?
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ module.exports = {
|
||||
'ms': 0.001
|
||||
},
|
||||
angle: {
|
||||
'rad': 1/(2*Math.PI),
|
||||
'deg': 1/360,
|
||||
'grad': 1/400,
|
||||
'rad': 1 / (2 * Math.PI),
|
||||
'deg': 1 / 360,
|
||||
'grad': 1 / 400,
|
||||
'turn': 1
|
||||
}
|
||||
};
|
||||
@@ -53,10 +53,10 @@ abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) {
|
||||
}
|
||||
baseUrlDirectories = baseUrlParts.directories.slice(i);
|
||||
urlDirectories = urlParts.directories.slice(i);
|
||||
for(i = 0; i < baseUrlDirectories.length-1; i++) {
|
||||
for(i = 0; i < baseUrlDirectories.length - 1; i++) {
|
||||
diff += "../";
|
||||
}
|
||||
for(i = 0; i < urlDirectories.length-1; i++) {
|
||||
for(i = 0; i < urlDirectories.length - 1; i++) {
|
||||
diff += urlDirectories[i] + "/";
|
||||
}
|
||||
return diff;
|
||||
@@ -81,7 +81,7 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
|
||||
if (baseUrl && (!urlParts[1] || urlParts[2])) {
|
||||
baseUrlParts = baseUrl.match(urlPartsRegex);
|
||||
if (!baseUrlParts) {
|
||||
throw new Error("Could not parse page url - '"+baseUrl+"'");
|
||||
throw new Error("Could not parse page url - '" + baseUrl + "'");
|
||||
}
|
||||
urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
|
||||
if (!urlParts[2]) {
|
||||
@@ -102,7 +102,7 @@ abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, ba
|
||||
|
||||
for(i = 0; i < directories.length; i++) {
|
||||
if (directories[i] === ".." && i > 0) {
|
||||
directories.splice(i-1, 2);
|
||||
directories.splice(i - 1, 2);
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ var colorBlendModeFunctions = {
|
||||
},
|
||||
overlay: function(cb, cs) {
|
||||
cb *= 2;
|
||||
return (cb <= 1)
|
||||
? colorBlendModeFunctions.multiply(cb, cs)
|
||||
: colorBlendModeFunctions.screen(cb - 1, cs);
|
||||
return (cb <= 1) ?
|
||||
colorBlendModeFunctions.multiply(cb, cs) :
|
||||
colorBlendModeFunctions.screen(cb - 1, cs);
|
||||
},
|
||||
softlight: function(cb, cs) {
|
||||
var d = 1, e = cb;
|
||||
|
||||
@@ -47,7 +47,7 @@ colorFunctions = {
|
||||
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
|
||||
if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; }
|
||||
else if (h * 2 < 1) { return m2; }
|
||||
else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; }
|
||||
else if (h * 3 < 2) { return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
|
||||
else { return m1; }
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ colorFunctions = {
|
||||
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
|
||||
var m1 = l * 2 - m2;
|
||||
|
||||
return colorFunctions.rgba(hue(h + 1/3) * 255,
|
||||
return colorFunctions.rgba(hue(h + 1 / 3) * 255,
|
||||
hue(h) * 255,
|
||||
hue(h - 1/3) * 255,
|
||||
hue(h - 1 / 3) * 255,
|
||||
a);
|
||||
},
|
||||
|
||||
@@ -127,9 +127,9 @@ colorFunctions = {
|
||||
},
|
||||
luminance: function (color) {
|
||||
var luminance =
|
||||
(0.2126 * color.rgb[0] / 255)
|
||||
+ (0.7152 * color.rgb[1] / 255)
|
||||
+ (0.0722 * color.rgb[2] / 255);
|
||||
(0.2126 * color.rgb[0] / 255) +
|
||||
(0.7152 * color.rgb[1] / 255) +
|
||||
(0.0722 * color.rgb[2] / 255);
|
||||
|
||||
return new Dimension(luminance * color.alpha * 100, '%');
|
||||
},
|
||||
@@ -268,7 +268,7 @@ colorFunctions = {
|
||||
};
|
||||
},
|
||||
tint: function(color, amount) {
|
||||
return colorFunctions.mix(colorFunctions.rgb(255,255,255), color, amount);
|
||||
return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount);
|
||||
},
|
||||
shade: function(color, amount) {
|
||||
return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount);
|
||||
|
||||
@@ -16,12 +16,13 @@ module.exports = function(environment) {
|
||||
|
||||
var mimetype = mimetypeNode && mimetypeNode.value;
|
||||
var filePath = filePathNode.value;
|
||||
var currentDirectory = filePathNode.currentFileInfo.relativeUrls ?
|
||||
filePathNode.currentFileInfo.currentDirectory : filePathNode.currentFileInfo.entryPath;
|
||||
var currentFileInfo = this.currentFileInfo;
|
||||
var currentDirectory = currentFileInfo.relativeUrls ?
|
||||
currentFileInfo.currentDirectory : currentFileInfo.entryPath;
|
||||
|
||||
var fragmentStart = filePath.indexOf('#');
|
||||
var fragment = '';
|
||||
if (fragmentStart!==-1) {
|
||||
if (fragmentStart !== -1) {
|
||||
fragment = filePath.slice(fragmentStart);
|
||||
filePath = filePath.slice(0, fragmentStart);
|
||||
}
|
||||
@@ -39,7 +40,7 @@ module.exports = function(environment) {
|
||||
|
||||
mimetype = environment.mimeLookup(filePath);
|
||||
|
||||
if (mimetype === "image/svg+xml") {
|
||||
if (mimetype === "image/svg+xml") {
|
||||
useBase64 = false;
|
||||
} else {
|
||||
// use base 64 unless it's an ASCII or UTF-8 format
|
||||
@@ -54,29 +55,30 @@ module.exports = function(environment) {
|
||||
|
||||
var fileSync = fileManager.loadFileSync(filePath, currentDirectory, this.context, environment);
|
||||
if (!fileSync.contents) {
|
||||
logger.warn("Skipped data-uri embedding because file not found");
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because file not found");
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
var buf = fileSync.contents;
|
||||
if (useBase64 && !environment.encodeBase64) {
|
||||
return fallback(this, filePathNode);
|
||||
}
|
||||
if (useBase64 && !environment.encodeBase64) {
|
||||
return fallback(this, filePathNode);
|
||||
}
|
||||
|
||||
buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);
|
||||
|
||||
var uri = "data:" + mimetype + ',' + buf + fragment;
|
||||
|
||||
// IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
|
||||
// and the --ieCompat flag is enabled, return a normal url() instead.
|
||||
var DATA_URI_MAX = 32768;
|
||||
if (uri.length >= DATA_URI_MAX) {
|
||||
// IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
|
||||
// and the --ieCompat flag is enabled, return a normal url() instead.
|
||||
var DATA_URI_MAX = 32768;
|
||||
if (uri.length >= DATA_URI_MAX) {
|
||||
|
||||
if (this.context.ieCompat !== false) {
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length + " characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
|
||||
if (this.context.ieCompat !== false) {
|
||||
logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length +
|
||||
" characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
|
||||
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
}
|
||||
return fallback(this, filePathNode || mimetypeNode);
|
||||
}
|
||||
}
|
||||
|
||||
return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,9 @@ functionRegistry.addMultiple({
|
||||
return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value);
|
||||
},
|
||||
escape: function (str) {
|
||||
return new Anonymous(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
|
||||
return new Anonymous(
|
||||
encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B")
|
||||
.replace(/\(/g, "%28").replace(/\)/g, "%29"));
|
||||
},
|
||||
replace: function (string, pattern, replacement, flags) {
|
||||
var result = string.value;
|
||||
|
||||
@@ -9,7 +9,9 @@ module.exports = function(environment) {
|
||||
functionRegistry.add("svg-gradient", function(direction) {
|
||||
|
||||
function throwArgumentDescriptor() {
|
||||
throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
|
||||
throw { type: "Argument",
|
||||
message: "svg-gradient expects direction, start_color [start_position], [color position,]...," +
|
||||
" end_color [end_position]" };
|
||||
}
|
||||
|
||||
if (arguments.length < 3) {
|
||||
@@ -44,7 +46,8 @@ module.exports = function(environment) {
|
||||
rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
|
||||
break;
|
||||
default:
|
||||
throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
|
||||
throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right'," +
|
||||
" 'to bottom right', 'to top right' or 'ellipse at center'" };
|
||||
}
|
||||
returner = '<?xml version="1.0" ?>' +
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
|
||||
@@ -59,7 +62,7 @@ module.exports = function(environment) {
|
||||
position = undefined;
|
||||
}
|
||||
|
||||
if (!(color instanceof Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
|
||||
if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
|
||||
throwArgumentDescriptor();
|
||||
}
|
||||
positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var Keyword = require("../tree/keyword"),
|
||||
DetachedRuleset = require("../tree/detached-ruleset"),
|
||||
Dimension = require("../tree/dimension"),
|
||||
Color = require("../tree/color"),
|
||||
Quoted = require("../tree/quoted"),
|
||||
@@ -21,6 +22,9 @@ var isa = function (n, Type) {
|
||||
return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;
|
||||
};
|
||||
functionRegistry.addMultiple({
|
||||
isruleset: function (n) {
|
||||
return isa(n, DetachedRuleset);
|
||||
},
|
||||
iscolor: function (n) {
|
||||
return isa(n, Color);
|
||||
},
|
||||
@@ -48,7 +52,9 @@ functionRegistry.addMultiple({
|
||||
isunit: isunit,
|
||||
unit: function (val, unit) {
|
||||
if(!(val instanceof Dimension)) {
|
||||
throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof Operation ? ". Have you forgotten parenthesis?" : "") };
|
||||
throw { type: "Argument",
|
||||
message: "the first argument to unit must be a number" +
|
||||
(val instanceof Operation ? ". Have you forgotten parenthesis?" : "") };
|
||||
}
|
||||
if (unit) {
|
||||
if (unit instanceof Keyword) {
|
||||
|
||||
@@ -40,12 +40,14 @@ module.exports = function(environment) {
|
||||
importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue
|
||||
|
||||
var importedEqualsRoot = fullPath === importManager.rootFilename;
|
||||
|
||||
if (importOptions.optional && e) {
|
||||
callback(null, {rules:[]}, false, null);
|
||||
}
|
||||
else {
|
||||
importManager.files[fullPath] = root;
|
||||
|
||||
if (e && !importManager.error) { importManager.error = e; }
|
||||
|
||||
callback(e, root, importedEqualsRoot, fullPath);
|
||||
}
|
||||
};
|
||||
|
||||
var newFileInfo = {
|
||||
@@ -68,7 +70,7 @@ module.exports = function(environment) {
|
||||
|
||||
var loadFileCallback = function(loadedFile) {
|
||||
var resolvedFilename = loadedFile.filename,
|
||||
contents = loadedFile.contents;
|
||||
contents = loadedFile.contents.replace(/^\uFEFF/, '');
|
||||
|
||||
// Pass on an updated rootpath if path of imported file is relative and file
|
||||
// is in a (sub|sup) directory
|
||||
@@ -80,7 +82,10 @@ module.exports = function(environment) {
|
||||
// then rootpath should become 'less/../'
|
||||
newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
|
||||
if(newFileInfo.relativeUrls) {
|
||||
newFileInfo.rootpath = fileManager.join((importManager.context.rootpath || ""), fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
|
||||
newFileInfo.rootpath = fileManager.join(
|
||||
(importManager.context.rootpath || ""),
|
||||
fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
|
||||
|
||||
if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
|
||||
newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ module.exports = function(environment, fileManagers) {
|
||||
var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
|
||||
|
||||
var less = {
|
||||
version: [2, 2, 0],
|
||||
version: [2, 3, 0],
|
||||
data: require('./data'),
|
||||
tree: require('./tree'),
|
||||
Environment: (Environment = require("./environment/environment")),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var LessError = require('./less-error'),
|
||||
transformTree = require("./transform-tree"),
|
||||
logger = require("./logger");
|
||||
logger = require("./logger");
|
||||
|
||||
module.exports = function(SourceMapBuilder) {
|
||||
var ParseTree = function(root, imports) {
|
||||
@@ -17,11 +17,11 @@ ParseTree.prototype.toCSS = function(options) {
|
||||
}
|
||||
|
||||
try {
|
||||
var compress = Boolean(options.compress);
|
||||
if (compress) {
|
||||
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
|
||||
}
|
||||
|
||||
var compress = Boolean(options.compress);
|
||||
if (compress) {
|
||||
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
|
||||
}
|
||||
|
||||
var toCSSOptions = {
|
||||
compress: compress,
|
||||
dumpLineNumbers: options.dumpLineNumbers,
|
||||
|
||||
@@ -46,6 +46,10 @@ module.exports = function(environment, ParseTree, ImportManager) {
|
||||
entryPath: entryPath,
|
||||
rootFilename: filename
|
||||
};
|
||||
// add in a missing trailing slash
|
||||
if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== "/") {
|
||||
rootFileInfo.rootpath += "/";
|
||||
}
|
||||
}
|
||||
|
||||
var imports = new ImportManager(context, rootFileInfo);
|
||||
|
||||
@@ -204,7 +204,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
// Ruleset (Selector '.class', [
|
||||
// Rule ("color", Value ([Expression [Color #fff]]))
|
||||
// Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
|
||||
// Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
|
||||
// Rule ("width", Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]]))
|
||||
// Ruleset (Selector [Element '>', '.child'], [...])
|
||||
// ])
|
||||
//
|
||||
@@ -231,13 +231,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
primary: function () {
|
||||
var mixin = this.mixin, root = [], node;
|
||||
|
||||
while (!parserInput.finished)
|
||||
while (true)
|
||||
{
|
||||
while(true) {
|
||||
node = this.comment();
|
||||
if (!node) { break; }
|
||||
root.push(node);
|
||||
}
|
||||
// always process comments before deciding if finished
|
||||
if (parserInput.finished) {
|
||||
break;
|
||||
}
|
||||
if (parserInput.peek('}')) {
|
||||
break;
|
||||
}
|
||||
@@ -450,7 +454,9 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
var rgb;
|
||||
|
||||
if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
|
||||
var colorCandidateString = rgb.input.match(/^#([\w]+).*/); // strip colons, brackets, whitespaces and other characters that should not definitely be part of color string
|
||||
// strip colons, brackets, whitespaces and other characters that should not
|
||||
// definitely be part of color string
|
||||
var colorCandidateString = rgb.input.match(/^#([\w]+).*/);
|
||||
colorCandidateString = colorCandidateString[1];
|
||||
if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
|
||||
error("Invalid HEX color code");
|
||||
@@ -546,8 +552,9 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
}
|
||||
|
||||
option = option && option[1];
|
||||
if (!elements)
|
||||
if (!elements) {
|
||||
error("Missing target selector for :extend().");
|
||||
}
|
||||
extend = new(tree.Extend)(new(tree.Selector)(elements), option, index);
|
||||
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
||||
|
||||
@@ -857,11 +864,12 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
|
||||
c = this.combinator();
|
||||
|
||||
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) || parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
||||
parserInput.$char('*') || parserInput.$char('&') || this.attribute() || parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#](?=@)/) ||
|
||||
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
|
||||
parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
||||
parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
|
||||
parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
|
||||
this.entities.variableCurly();
|
||||
|
||||
|
||||
if (! e) {
|
||||
parserInput.save();
|
||||
if (parserInput.$char('(')) {
|
||||
@@ -1170,7 +1178,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
},
|
||||
|
||||
importOption: function() {
|
||||
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference)/);
|
||||
var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
|
||||
if (opt) {
|
||||
return opt[1];
|
||||
}
|
||||
@@ -1384,19 +1392,19 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
sub: function () {
|
||||
var a, e;
|
||||
|
||||
parserInput.save();
|
||||
parserInput.save();
|
||||
if (parserInput.$char('(')) {
|
||||
a = this.addition();
|
||||
if (a && parserInput.$char(')')) {
|
||||
parserInput.forget();
|
||||
e = new(tree.Expression)([a]);
|
||||
e.parens = true;
|
||||
parserInput.forget();
|
||||
e = new(tree.Expression)([a]);
|
||||
e.parens = true;
|
||||
return e;
|
||||
}
|
||||
parserInput.restore("Expected ')'");
|
||||
return;
|
||||
parserInput.restore("Expected ')'");
|
||||
return;
|
||||
}
|
||||
parserInput.restore();
|
||||
parserInput.restore();
|
||||
},
|
||||
multiplication: function () {
|
||||
var m, a, op, operation, isSpaced;
|
||||
@@ -1603,8 +1611,8 @@ Parser.serializeVars = function(vars) {
|
||||
for (var name in vars) {
|
||||
if (Object.hasOwnProperty.call(vars, name)) {
|
||||
var value = vars[name];
|
||||
s += ((name[0] === '@') ? '' : '@') + name +': '+ value +
|
||||
((('' + value).slice(-1) === ';') ? '' : ';');
|
||||
s += ((name[0] === '@') ? '' : '@') + name + ': ' + value +
|
||||
((String(value).slice(-1) === ';') ? '' : ';');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ module.exports = function (environment) {
|
||||
}
|
||||
if (options.sourceMapRootpath) {
|
||||
this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
|
||||
if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1) !== '/') {
|
||||
if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
|
||||
this._sourceMapRootpath += '/';
|
||||
}
|
||||
} else {
|
||||
@@ -66,11 +66,11 @@ module.exports = function (environment) {
|
||||
}
|
||||
inputSource = inputSource.substring(0, index);
|
||||
sourceLines = inputSource.split("\n");
|
||||
sourceColumns = sourceLines[sourceLines.length-1];
|
||||
sourceColumns = sourceLines[sourceLines.length - 1];
|
||||
}
|
||||
|
||||
lines = chunk.split("\n");
|
||||
columns = lines[lines.length-1];
|
||||
columns = lines[lines.length - 1];
|
||||
|
||||
if (fileInfo) {
|
||||
if (!mapLines) {
|
||||
|
||||
@@ -45,7 +45,7 @@ module.exports = function(root, options) {
|
||||
|
||||
if (options.pluginManager) {
|
||||
var pluginVisitors = options.pluginManager.getVisitors();
|
||||
for(i =0; i < pluginVisitors.length; i++) {
|
||||
for(i = 0; i < pluginVisitors.length; i++) {
|
||||
var pluginVisitor = pluginVisitors[i];
|
||||
if (pluginVisitor.isPreEvalVisitor) {
|
||||
preEvalVisitors.push(pluginVisitor);
|
||||
|
||||
@@ -25,4 +25,3 @@ Assignment.prototype.genCSS = function (context, output) {
|
||||
}
|
||||
};
|
||||
module.exports = Assignment;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Condition.prototype.eval = function (context) {
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}) (this.op, this.lvalue.eval(context), this.rvalue.eval(context));
|
||||
})(this.op, this.lvalue.eval(context), this.rvalue.eval(context));
|
||||
|
||||
return this.negate ? !result : result;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var debugInfo = function(context, ctx, lineSeparator) {
|
||||
var result="";
|
||||
var result = "";
|
||||
if (context.dumpLineNumbers && !context.compress) {
|
||||
switch(context.dumpLineNumbers) {
|
||||
case 'comments':
|
||||
@@ -21,8 +21,12 @@ debugInfo.asComment = function(ctx) {
|
||||
};
|
||||
|
||||
debugInfo.asMediaQuery = function(ctx) {
|
||||
var filenameWithProtocol = ctx.debugInfo.fileName;
|
||||
if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
|
||||
filenameWithProtocol = 'file://' + filenameWithProtocol;
|
||||
}
|
||||
return '@media -sass-debug-info{filename{font-family:' +
|
||||
('file://' + ctx.debugInfo.fileName).replace(/([.:\/\\])/g, function (a) {
|
||||
filenameWithProtocol.replace(/([.:\/\\])/g, function (a) {
|
||||
if (a == '\\') {
|
||||
a = '\/';
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ Dimension.prototype.toColor = function () {
|
||||
};
|
||||
Dimension.prototype.genCSS = function (context, output) {
|
||||
if ((context && context.strictUnits) && !this.unit.isSingular()) {
|
||||
throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());
|
||||
throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: " + this.unit.toString());
|
||||
}
|
||||
|
||||
var value = this.fround(context, this.value),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var Node = require("./node"),
|
||||
Ruleset = require("./ruleset");
|
||||
|
||||
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo) {
|
||||
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isReferenced) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
if (rules) {
|
||||
@@ -11,6 +11,7 @@ var Directive = function (name, value, rules, index, currentFileInfo, debugInfo)
|
||||
this.index = index;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
this.debugInfo = debugInfo;
|
||||
this.isReferenced = isReferenced;
|
||||
};
|
||||
|
||||
Directive.prototype = new Node();
|
||||
@@ -38,9 +39,9 @@ Directive.prototype.genCSS = function (context, output) {
|
||||
value.genCSS(context, output);
|
||||
}
|
||||
if (rules) {
|
||||
if (rules.type === "Ruleset") {
|
||||
rules = [rules];
|
||||
}
|
||||
if (rules.type === "Ruleset") {
|
||||
rules = [rules];
|
||||
}
|
||||
this.outputRuleset(context, output, rules);
|
||||
} else {
|
||||
output.add(';');
|
||||
@@ -56,11 +57,23 @@ Directive.prototype.eval = function (context) {
|
||||
rules.root = true;
|
||||
}
|
||||
return new Directive(this.name, value, rules,
|
||||
this.index, this.currentFileInfo, this.debugInfo);
|
||||
this.index, this.currentFileInfo, this.debugInfo, this.isReferenced);
|
||||
};
|
||||
Directive.prototype.variable = function (name) {
|
||||
if (this.rules) {
|
||||
return Ruleset.prototype.variable.call(this.rules, name);
|
||||
}
|
||||
};
|
||||
Directive.prototype.find = function () {
|
||||
if (this.rules) {
|
||||
return Ruleset.prototype.find.apply(this.rules, arguments);
|
||||
}
|
||||
};
|
||||
Directive.prototype.rulesets = function () {
|
||||
if (this.rules) {
|
||||
return Ruleset.prototype.rulesets.apply(this.rules);
|
||||
}
|
||||
};
|
||||
Directive.prototype.variable = function (name) { if (this.rules) return Ruleset.prototype.variable.call(this.rules, name); };
|
||||
Directive.prototype.find = function () { if (this.rules) return Ruleset.prototype.find.apply(this.rules, arguments); };
|
||||
Directive.prototype.rulesets = function () { if (this.rules) return Ruleset.prototype.rulesets.apply(this.rules); };
|
||||
Directive.prototype.markReferenced = function () {
|
||||
var i, rules;
|
||||
this.isReferenced = true;
|
||||
@@ -73,6 +86,9 @@ Directive.prototype.markReferenced = function () {
|
||||
}
|
||||
}
|
||||
};
|
||||
Directive.prototype.getIsReferenced = function () {
|
||||
return !this.currentFileInfo || !this.currentFileInfo.reference || this.isReferenced;
|
||||
};
|
||||
Directive.prototype.outputRuleset = function (context, output, rules) {
|
||||
var ruleCnt = rules.length, i;
|
||||
context.tabLevel = (context.tabLevel | 0) + 1;
|
||||
|
||||
@@ -100,7 +100,7 @@ Import.prototype.evalPath = function (context) {
|
||||
var pathValue = path.value;
|
||||
// Add the base path if the import is relative
|
||||
if (pathValue && context.isPathRelative(pathValue)) {
|
||||
path.value = rootpath +pathValue;
|
||||
path.value = rootpath + pathValue;
|
||||
}
|
||||
}
|
||||
path.value = context.normalizePath(path.value);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var tree = {};
|
||||
|
||||
tree.Node = require('./node');
|
||||
tree.Alpha = require('./alpha');
|
||||
tree.Color = require('./color');
|
||||
tree.Directive = require('./directive');
|
||||
|
||||
@@ -154,8 +154,9 @@ Media.prototype.permute = function (arr) {
|
||||
}
|
||||
};
|
||||
Media.prototype.bubbleSelectors = function (selectors) {
|
||||
if (!selectors)
|
||||
return;
|
||||
if (!selectors) {
|
||||
return;
|
||||
}
|
||||
this.rules = [new Ruleset(selectors.slice(0), [this.rules[0]])];
|
||||
};
|
||||
module.exports = Media;
|
||||
|
||||
@@ -22,7 +22,7 @@ MixinCall.prototype.accept = function (visitor) {
|
||||
};
|
||||
MixinCall.prototype.eval = function (context) {
|
||||
var mixins, mixin, mixinPath, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
|
||||
candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase=-1,
|
||||
candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1,
|
||||
defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter;
|
||||
|
||||
function calcDefGroup(mixin, mixinPath) {
|
||||
@@ -84,7 +84,7 @@ MixinCall.prototype.eval = function (context) {
|
||||
if (mixin.matchArgs(args, context)) {
|
||||
candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)};
|
||||
|
||||
if (candidate.group!==defFalseEitherCase) {
|
||||
if (candidate.group !== defFalseEitherCase) {
|
||||
candidates.push(candidate);
|
||||
}
|
||||
|
||||
@@ -105,8 +105,7 @@ MixinCall.prototype.eval = function (context) {
|
||||
defaultResult = defTrue;
|
||||
if ((count[defTrue] + count[defFalse]) > 1) {
|
||||
throw { type: 'Runtime',
|
||||
message: 'Ambiguous use of `default()` found when matching for `'
|
||||
+ this.format(args) + '`',
|
||||
message: 'Ambiguous use of `default()` found when matching for `' + this.format(args) + '`',
|
||||
index: this.index, filename: this.currentFileInfo.filename };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,9 +132,10 @@ Definition.prototype.evalCall = function (context, args, important) {
|
||||
Definition.prototype.matchCondition = function (args, context) {
|
||||
if (this.condition && !this.condition.eval(
|
||||
new contexts.Eval(context,
|
||||
[this.evalParams(context, new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])] // the parameter variables
|
||||
.concat(this.frames) // the parent namespace/mixin frames
|
||||
.concat(context.frames)))) { // the current environment frames
|
||||
[this.evalParams(context, /* the parameter variables*/
|
||||
new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
|
||||
.concat(this.frames) // the parent namespace/mixin frames
|
||||
.concat(context.frames)))) { // the current environment frames
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -37,7 +37,7 @@ Quoted.prototype.eval = function (context) {
|
||||
do {
|
||||
value = evaluatedValue;
|
||||
evaluatedValue = value.replace(regexp, replacementFnc);
|
||||
} while (value!==evaluatedValue);
|
||||
} while (value !== evaluatedValue);
|
||||
return evaluatedValue;
|
||||
}
|
||||
value = iterativeReplace(value, /`([^`]+)`/g, javascriptReplacement);
|
||||
|
||||
@@ -42,9 +42,8 @@ Rule.prototype.eval = function (context) {
|
||||
if (typeof name !== "string") {
|
||||
// expand 'primitive' name directly to get
|
||||
// things faster (~10% for benchmark.less):
|
||||
name = (name.length === 1)
|
||||
&& (name[0] instanceof Keyword)
|
||||
? name[0].value : evalName(context, name);
|
||||
name = (name.length === 1) && (name[0] instanceof Keyword) ?
|
||||
name[0].value : evalName(context, name);
|
||||
variable = false; // never treat expanded interpolation as new variable name
|
||||
}
|
||||
if (name === "font" && !context.strictMath) {
|
||||
|
||||
@@ -108,7 +108,7 @@ Ruleset.prototype.eval = function (context) {
|
||||
});
|
||||
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
||||
rsRuleCnt += rules.length - 1;
|
||||
i += rules.length-1;
|
||||
i += rules.length - 1;
|
||||
ruleset.resetCache();
|
||||
} else if (rsRules[i].type === "RulesetCall") {
|
||||
/*jshint loopfunc:true */
|
||||
@@ -121,7 +121,7 @@ Ruleset.prototype.eval = function (context) {
|
||||
});
|
||||
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
||||
rsRuleCnt += rules.length - 1;
|
||||
i += rules.length-1;
|
||||
i += rules.length - 1;
|
||||
ruleset.resetCache();
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ Ruleset.prototype.evalImports = function(context) {
|
||||
importRules = rules[i].eval(context);
|
||||
if (importRules && importRules.length) {
|
||||
rules.splice.apply(rules, [i, 1].concat(importRules));
|
||||
i+= importRules.length-1;
|
||||
i+= importRules.length - 1;
|
||||
} else {
|
||||
rules.splice(i, 1, importRules);
|
||||
}
|
||||
@@ -183,20 +183,20 @@ Ruleset.prototype.evalImports = function(context) {
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.makeImportant = function() {
|
||||
return new Ruleset(this.selectors, this.rules.map(function (r) {
|
||||
if (r.makeImportant) {
|
||||
return r.makeImportant();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}), this.strictImports);
|
||||
};
|
||||
Ruleset.prototype.matchArgs = function (args) {
|
||||
this.rules = this.rules.map(function (r) {
|
||||
if (r.makeImportant) {
|
||||
return r.makeImportant();
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};Ruleset.prototype.matchArgs = function (args) {
|
||||
return !args || args.length === 0;
|
||||
};
|
||||
// lets you call a css selector with a guard
|
||||
Ruleset.prototype.matchCondition = function (args, context) {
|
||||
var lastSelector = this.selectors[this.selectors.length-1];
|
||||
var lastSelector = this.selectors[this.selectors.length - 1];
|
||||
if (!lastSelector.evaldCondition) {
|
||||
return false;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ Ruleset.prototype.variables = function () {
|
||||
}
|
||||
// when evaluating variables in an import statement, imports have not been eval'd
|
||||
// so we need to go inside import statements.
|
||||
// guard against root being a string (in the case of inlined less)
|
||||
// guard against root being a string (in the case of inlined less)
|
||||
if (r.type === "Import" && r.root && r.root.variables) {
|
||||
var vars = r.root.variables();
|
||||
for(var name in vars) {
|
||||
@@ -415,13 +415,46 @@ Ruleset.prototype.genCSS = function (context, output) {
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.markReferenced = function () {
|
||||
if (!this.selectors) {
|
||||
return;
|
||||
var s;
|
||||
if (this.selectors) {
|
||||
for (s = 0; s < this.selectors.length; s++) {
|
||||
this.selectors[s].markReferenced();
|
||||
}
|
||||
}
|
||||
for (var s = 0; s < this.selectors.length; s++) {
|
||||
this.selectors[s].markReferenced();
|
||||
|
||||
if (this.rules) {
|
||||
for (s = 0; s < this.rules.length; s++) {
|
||||
if (this.rules[s].markReferenced) {
|
||||
this.rules[s].markReferenced();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ruleset.prototype.getIsReferenced = function() {
|
||||
var i, j, path, selector;
|
||||
|
||||
if (this.paths) {
|
||||
for (i = 0; i < this.paths.length; i++) {
|
||||
path = this.paths[i];
|
||||
for (j = 0; j < path.length; j++) {
|
||||
if (path[j].getIsReferenced && path[j].getIsReferenced()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectors) {
|
||||
for (i = 0; i < this.selectors.length; i++) {
|
||||
selector = this.selectors[i];
|
||||
if (selector.getIsReferenced && selector.getIsReferenced()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
|
||||
for (var s = 0; s < selectors.length; s++) {
|
||||
this.joinSelector(paths, context, selectors[s]);
|
||||
@@ -468,12 +501,14 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false;
|
||||
function findNestedSelector(element) {
|
||||
var maybeSelector;
|
||||
if (element.value.type !== 'Paren')
|
||||
if (element.value.type !== 'Paren') {
|
||||
return null;
|
||||
}
|
||||
|
||||
maybeSelector = element.value.value;
|
||||
if (maybeSelector.type !== 'Selector')
|
||||
if (maybeSelector.type !== 'Selector') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return maybeSelector;
|
||||
}
|
||||
@@ -669,4 +704,4 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
}
|
||||
|
||||
};
|
||||
module.exports = Ruleset;
|
||||
module.exports = Ruleset;
|
||||
|
||||
@@ -51,8 +51,9 @@ Selector.prototype.match = function (other) {
|
||||
return olen; // return number of matched elements
|
||||
};
|
||||
Selector.prototype.CacheElements = function() {
|
||||
if (this._elements)
|
||||
if (this._elements) {
|
||||
return;
|
||||
}
|
||||
|
||||
var elements = this.elements.map( function(v) {
|
||||
return v.combinator.value + (v.value.value || v.value);
|
||||
|
||||
@@ -28,7 +28,7 @@ URL.prototype.eval = function (context) {
|
||||
context.isPathRelative(val.value)) {
|
||||
|
||||
if (!val.quote) {
|
||||
rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
|
||||
rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\" + match; });
|
||||
}
|
||||
val.value = rootpath + val.value;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ Value.prototype.genCSS = function (context, output) {
|
||||
var i;
|
||||
for(i = 0; i < this.value.length; i++) {
|
||||
this.value[i].genCSS(context, output);
|
||||
if (i+1 < this.value.length) {
|
||||
if (i + 1 < this.value.length) {
|
||||
output.add((context && context.compress) ? ',' : ', ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ Variable.prototype.eval = function (context) {
|
||||
var v = frame.variable(name);
|
||||
if (v) {
|
||||
if (v.important) {
|
||||
var importantScope = context.importantScope[context.importantScope.length-1];
|
||||
var importantScope = context.importantScope[context.importantScope.length - 1];
|
||||
importantScope.important = v.important;
|
||||
}
|
||||
return v.value.eval(context);
|
||||
|
||||
@@ -61,7 +61,7 @@ ExtendFinderVisitor.prototype = {
|
||||
extend.findSelfSelectors(selectorPath);
|
||||
extend.ruleset = rulesetNode;
|
||||
if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
|
||||
this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
|
||||
this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,21 +116,22 @@ ProcessExtendsVisitor.prototype = {
|
||||
|
||||
if(!indicies[extend.index + ' ' + selector]) {
|
||||
indicies[extend.index + ' ' + selector] = true;
|
||||
logger.warn("extend '"+selector+"' has no matches");
|
||||
logger.warn("extend '" + selector + "' has no matches");
|
||||
}
|
||||
});
|
||||
},
|
||||
doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
|
||||
//
|
||||
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
|
||||
// the selector we would do normally, but we are also adding an extend with the same target selector
|
||||
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering
|
||||
// and pasting the selector we would do normally, but we are also adding an extend with the same target selector
|
||||
// this means this new extend can then go and alter other extends
|
||||
//
|
||||
// this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
|
||||
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
|
||||
// we look at each selector at a time, as is done in visitRuleset
|
||||
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already
|
||||
// processed if we look at each selector at a time, as is done in visitRuleset
|
||||
|
||||
var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
|
||||
var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath,
|
||||
extend, targetExtend, newExtend;
|
||||
|
||||
iterationCount = iterationCount || 0;
|
||||
|
||||
@@ -168,7 +169,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
newExtend.selfSelectors = newSelector;
|
||||
|
||||
// add the extend onto the list of extends for that selector
|
||||
newSelector[newSelector.length-1].extendList = [newExtend];
|
||||
newSelector[newSelector.length - 1].extendList = [newExtend];
|
||||
|
||||
// record that we need to add it.
|
||||
extendsToAdd.push(newExtend);
|
||||
@@ -202,11 +203,13 @@ ProcessExtendsVisitor.prototype = {
|
||||
selectorTwo = extendsToAdd[0].selector.toCSS();
|
||||
}
|
||||
catch(e) {}
|
||||
throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
|
||||
throw { message: "extend circular reference detected. One of the circular extends is currently:" +
|
||||
selectorOne + ":extend(" + selectorTwo + ")"};
|
||||
}
|
||||
|
||||
// now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
|
||||
return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
|
||||
// now process the new extends on the existing rules so that we can handle a extending b extending c extending
|
||||
// d extending e...
|
||||
return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
|
||||
} else {
|
||||
return extendsToAdd;
|
||||
}
|
||||
@@ -224,7 +227,8 @@ ProcessExtendsVisitor.prototype = {
|
||||
if (rulesetNode.root) {
|
||||
return;
|
||||
}
|
||||
var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
|
||||
var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1],
|
||||
selectorsToAdd = [], extendVisitor = this, selectorPath;
|
||||
|
||||
// look at each selector path in the ruleset, find any extend matches and then copy, find and replace
|
||||
|
||||
@@ -234,7 +238,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
|
||||
// extending extends happens initially, before the main pass
|
||||
if (rulesetNode.extendOnEveryPath) { continue; }
|
||||
var extendList = selectorPath[selectorPath.length-1].extendList;
|
||||
var extendList = selectorPath[selectorPath.length - 1].extendList;
|
||||
if (extendList && extendList.length) { continue; }
|
||||
|
||||
matches = this.findMatch(allExtends[extendIndex], selectorPath);
|
||||
@@ -271,15 +275,16 @@ ProcessExtendsVisitor.prototype = {
|
||||
|
||||
// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
|
||||
if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
|
||||
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
|
||||
potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
|
||||
initialCombinator: haystackElement.combinator});
|
||||
}
|
||||
|
||||
for(i = 0; i < potentialMatches.length; i++) {
|
||||
potentialMatch = potentialMatches[i];
|
||||
|
||||
// selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
|
||||
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
|
||||
// what the resulting combinator will be
|
||||
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to
|
||||
// work out what the resulting combinator will be
|
||||
targetCombinator = haystackElement.combinator.value;
|
||||
if (targetCombinator === '' && hackstackElementIndex === 0) {
|
||||
targetCombinator = ' ';
|
||||
@@ -297,7 +302,8 @@ ProcessExtendsVisitor.prototype = {
|
||||
if (potentialMatch) {
|
||||
potentialMatch.finished = potentialMatch.matched === needleElements.length;
|
||||
if (potentialMatch.finished &&
|
||||
(!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
|
||||
(!extend.allowAfter &&
|
||||
(hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {
|
||||
potentialMatch = null;
|
||||
}
|
||||
}
|
||||
@@ -343,7 +349,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
|
||||
return false;
|
||||
}
|
||||
for(var i = 0; i <elementValue1.elements.length; i++) {
|
||||
for(var i = 0; i < elementValue1.elements.length; i++) {
|
||||
if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
|
||||
if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
|
||||
return false;
|
||||
@@ -381,7 +387,8 @@ ProcessExtendsVisitor.prototype = {
|
||||
);
|
||||
|
||||
if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
|
||||
path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
||||
path[path.length - 1].elements = path[path.length - 1]
|
||||
.elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
||||
currentSelectorPathElementIndex = 0;
|
||||
currentSelectorPathIndex++;
|
||||
}
|
||||
@@ -410,7 +417,8 @@ ProcessExtendsVisitor.prototype = {
|
||||
}
|
||||
|
||||
if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
|
||||
path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
||||
path[path.length - 1].elements = path[path.length - 1]
|
||||
.elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
||||
currentSelectorPathIndex++;
|
||||
}
|
||||
|
||||
@@ -421,7 +429,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
visitRulesetOut: function (rulesetNode) {
|
||||
},
|
||||
visitMedia: function (mediaNode, visitArgs) {
|
||||
var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
|
||||
var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
||||
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
|
||||
this.allExtendsStack.push(newAllExtends);
|
||||
},
|
||||
@@ -431,7 +439,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
this.allExtendsStack.length = lastIndex;
|
||||
},
|
||||
visitDirective: function (directiveNode, visitArgs) {
|
||||
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
|
||||
var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
||||
newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
|
||||
this.allExtendsStack.push(newAllExtends);
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ function ImportSequencer(onSequencerEmpty) {
|
||||
this.imports = [];
|
||||
this.variableImports = [];
|
||||
this._onSequencerEmpty = onSequencerEmpty;
|
||||
this._currentDepth = 0;
|
||||
this._currentDepth = 0;
|
||||
}
|
||||
|
||||
ImportSequencer.prototype.addImport = function(callback) {
|
||||
@@ -25,27 +25,27 @@ ImportSequencer.prototype.addVariableImport = function(callback) {
|
||||
};
|
||||
|
||||
ImportSequencer.prototype.tryRun = function() {
|
||||
this._currentDepth++;
|
||||
try {
|
||||
while(true) {
|
||||
while(this.imports.length > 0) {
|
||||
var importItem = this.imports[0];
|
||||
if (!importItem.isReady) {
|
||||
return;
|
||||
}
|
||||
this.imports = this.imports.slice(1);
|
||||
importItem.callback.apply(null, importItem.args);
|
||||
}
|
||||
if (this.variableImports.length === 0) {
|
||||
break;
|
||||
}
|
||||
var variableImport = this.variableImports[0];
|
||||
this.variableImports = this.variableImports.slice(1);
|
||||
variableImport();
|
||||
}
|
||||
} finally {
|
||||
this._currentDepth--;
|
||||
}
|
||||
this._currentDepth++;
|
||||
try {
|
||||
while(true) {
|
||||
while(this.imports.length > 0) {
|
||||
var importItem = this.imports[0];
|
||||
if (!importItem.isReady) {
|
||||
return;
|
||||
}
|
||||
this.imports = this.imports.slice(1);
|
||||
importItem.callback.apply(null, importItem.args);
|
||||
}
|
||||
if (this.variableImports.length === 0) {
|
||||
break;
|
||||
}
|
||||
var variableImport = this.variableImports[0];
|
||||
this.variableImports = this.variableImports.slice(1);
|
||||
variableImport();
|
||||
}
|
||||
} finally {
|
||||
this._currentDepth--;
|
||||
}
|
||||
if (this._currentDepth === 0 && this._onSequencerEmpty) {
|
||||
this._onSequencerEmpty();
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ ImportVisitor.prototype = {
|
||||
this.isFinished = true;
|
||||
this._sequencer.tryRun();
|
||||
},
|
||||
_onSequencerEmpty: function() {
|
||||
if (!this.isFinished) {
|
||||
return;
|
||||
}
|
||||
this._finish(this.error);
|
||||
},
|
||||
_onSequencerEmpty: function() {
|
||||
if (!this.isFinished) {
|
||||
return;
|
||||
}
|
||||
this._finish(this.error);
|
||||
},
|
||||
visitImport: function (importNode, visitArgs) {
|
||||
var inlineCSS = importNode.options.inline;
|
||||
|
||||
@@ -84,12 +84,13 @@ ImportVisitor.prototype = {
|
||||
var onImported = this.onImported.bind(this, evaldImportNode, context),
|
||||
sequencedOnImported = this._sequencer.addImport(onImported);
|
||||
|
||||
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo, evaldImportNode.options, sequencedOnImported);
|
||||
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.currentFileInfo,
|
||||
evaldImportNode.options, sequencedOnImported);
|
||||
} else {
|
||||
this.importCount--;
|
||||
if (this.isFinished) {
|
||||
this._sequencer.tryRun();
|
||||
}
|
||||
if (this.isFinished) {
|
||||
this._sequencer.tryRun();
|
||||
}
|
||||
}
|
||||
},
|
||||
onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
|
||||
@@ -139,7 +140,7 @@ ImportVisitor.prototype = {
|
||||
importVisitor.importCount--;
|
||||
|
||||
if (importVisitor.isFinished) {
|
||||
importVisitor._sequencer.tryRun();
|
||||
importVisitor._sequencer.tryRun();
|
||||
}
|
||||
},
|
||||
visitRule: function (ruleNode, visitArgs) {
|
||||
|
||||
@@ -46,16 +46,16 @@ ToCSSVisitor.prototype = {
|
||||
},
|
||||
|
||||
visitDirective: function(directiveNode, visitArgs) {
|
||||
if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
|
||||
return;
|
||||
}
|
||||
if (directiveNode.name === "@charset") {
|
||||
if (!directiveNode.getIsReferenced()) {
|
||||
return;
|
||||
}
|
||||
// Only output the debug info together with subsequent @charset definitions
|
||||
// a comment (or @media statement) before the actual @charset directive would
|
||||
// be considered illegal css as it has to be on the first line
|
||||
if (this.charset) {
|
||||
if (directiveNode.debugInfo) {
|
||||
var comment = new tree.Comment("/* " + directiveNode.toCSS(this._context).replace(/\n/g, "")+" */\n");
|
||||
var comment = new tree.Comment("/* " + directiveNode.toCSS(this._context).replace(/\n/g, "") + " */\n");
|
||||
comment.debugInfo = directiveNode.debugInfo;
|
||||
return this._visitor.visit(comment);
|
||||
}
|
||||
@@ -65,6 +65,38 @@ ToCSSVisitor.prototype = {
|
||||
}
|
||||
if (directiveNode.rules && directiveNode.rules.rules) {
|
||||
this._mergeRules(directiveNode.rules.rules);
|
||||
//process childs
|
||||
directiveNode.accept(this._visitor);
|
||||
visitArgs.visitDeeper = false;
|
||||
|
||||
// the directive was directly referenced and therefore needs to be shown in the output
|
||||
if (directiveNode.getIsReferenced()) {
|
||||
return directiveNode;
|
||||
}
|
||||
|
||||
if (!directiveNode.rules.rules) {
|
||||
return ;
|
||||
}
|
||||
|
||||
//the directive was not directly referenced
|
||||
for (var r = 0; r < directiveNode.rules.rules.length; r++) {
|
||||
var rule = directiveNode.rules.rules[r];
|
||||
if (rule.getIsReferenced && rule.getIsReferenced()) {
|
||||
//the directive contains something that was referenced (likely by extend)
|
||||
//therefore it needs to be shown in output too
|
||||
|
||||
//marking as referenced in case the directive is stored inside another directive
|
||||
directiveNode.markReferenced();
|
||||
return directiveNode;
|
||||
}
|
||||
}
|
||||
//The directive was not directly referenced and does not contain anything that
|
||||
//was referenced. Therefore it must not be shown in output.
|
||||
return ;
|
||||
} else {
|
||||
if (!directiveNode.getIsReferenced()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return directiveNode;
|
||||
},
|
||||
@@ -225,7 +257,7 @@ ToCSSVisitor.prototype = {
|
||||
var spacedGroups = [];
|
||||
var lastSpacedGroup = [];
|
||||
parts.map(function (p) {
|
||||
if (p.merge==="+") {
|
||||
if (p.merge === "+") {
|
||||
if (lastSpacedGroup.length > 0) {
|
||||
spacedGroups.push(toExpression(lastSpacedGroup));
|
||||
}
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "less",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"description": "Leaner CSS",
|
||||
"homepage": "http://lesscss.org",
|
||||
"author": {
|
||||
@@ -40,13 +40,14 @@
|
||||
"test": "grunt test"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"errno": "^0.1.1",
|
||||
"graceful-fs": "^3.0.5",
|
||||
"image-size": "~0.3.5",
|
||||
"mime": "^1.2.11",
|
||||
"request": "^2.51.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"source-map": "^0.1.x",
|
||||
"promise": "^6.0.1",
|
||||
"image-size": "~0.3.5"
|
||||
"request": "^2.51.0",
|
||||
"source-map": "^0.1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"diff": "^1.0",
|
||||
@@ -57,6 +58,7 @@
|
||||
"grunt-contrib-jasmine": "^0.8.1",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-uglify": "^0.7.0",
|
||||
"grunt-jscs": "^1.2.0",
|
||||
"grunt-shell": "^1.1.1",
|
||||
"grunt-browserify": "^3.2.0",
|
||||
"matchdep": "^0.3.0",
|
||||
|
||||
@@ -130,10 +130,10 @@ var testErrorSheet = function (sheet) {
|
||||
.replace(/<h3>|<\/?p>|<a href="[^"]*">|<\/a>|<ul>|<\/?pre( class="?[^">]*"?)?>|<\/li>|<\/?label>/ig, "")
|
||||
.replace(/<\/h3>/ig, " ")
|
||||
.replace(/<li>|<\/ul>|<br>/ig, "\n"))
|
||||
.replace(/&/ig,"&")
|
||||
.replace(/&/ig, "&")
|
||||
// for IE8
|
||||
.replace(/\r\n/g,"\n")
|
||||
.replace(/\. \nin/,". in");
|
||||
.replace(/\r\n/g, "\n")
|
||||
.replace(/\. \nin/, ". in");
|
||||
actualErrorMsg = innerText
|
||||
.replace(/\n\d+/g, function (lineNo) {
|
||||
return lineNo + " ";
|
||||
@@ -149,7 +149,7 @@ var testErrorSheet = function (sheet) {
|
||||
.replace(/\{pathrel\}/g, "")
|
||||
.replace(/\{pathhref\}/g, "http://localhost:8081/test/less/errors/")
|
||||
.replace(/\{404status\}/g, " (404)")
|
||||
.replace(/\{node\}.*\{\/node\}/g, "")
|
||||
.replace(/\{node\}.*\{\/node\}/g, "")
|
||||
.replace(/\n$/, "");
|
||||
expect(actualErrorMsg).toEqual(errorTxt);
|
||||
if (errorTxt == actualErrorMsg) {
|
||||
|
||||
@@ -180,7 +180,6 @@
|
||||
// export public
|
||||
jasmine.JSReporter = JSReporter;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Jasmine JSReporter for Jasmine 2.0
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -240,7 +239,7 @@
|
||||
suite.specs = [];
|
||||
suite.suites = [];
|
||||
suite.passed = true;
|
||||
suite.parentId = this.suiteStack.slice(this.suiteStack.length -1)[0];
|
||||
suite.parentId = this.suiteStack.slice(this.suiteStack.length - 1)[0];
|
||||
if (suite.parentId) {
|
||||
this.suites[suite.parentId].suites.push(suite);
|
||||
} else {
|
||||
@@ -273,7 +272,7 @@
|
||||
spec = this._cacheSpec(spec);
|
||||
spec.timer = new Timer().start();
|
||||
// build up suites->spec tree as we go
|
||||
spec.suiteId = this.suiteStack.slice(this.suiteStack.length -1)[0];
|
||||
spec.suiteId = this.suiteStack.slice(this.suiteStack.length - 1)[0];
|
||||
this.suites[spec.suiteId].specs.push(spec);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@ var less = {
|
||||
strictUnits: true,
|
||||
strictMath: true,
|
||||
logLevel: 4 };
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
describe("less.js error tests", function() {
|
||||
testLessErrorsInDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -3,4 +3,3 @@ var less = {
|
||||
errorReporting: "console",
|
||||
strictMath: false,
|
||||
strictUnits: false };
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
describe("less.js javascript disabled error tests", function() {
|
||||
testLessErrorsInDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: "console"};
|
||||
less.env = "production";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: "console"};
|
||||
less.relativeUrls = true;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: "console"};
|
||||
less.rootpath = "https://localhost/";
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@ var less = {logLevel: 4,
|
||||
errorReporting: "console"};
|
||||
less.rootpath = "https://www.github.com/cloudhead/less.js/";
|
||||
less.relativeUrls = true;
|
||||
|
||||
|
||||
@@ -3,4 +3,3 @@ var less = {
|
||||
errorReporting: "console",
|
||||
strictMath: true,
|
||||
strictUnits: true };
|
||||
|
||||
|
||||
72
test/copy-bom.js
Normal file
72
test/copy-bom.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/*jshint latedef: nofunc */
|
||||
|
||||
// This is used to copy a folder (the test/less/* files & sub-folders), adding a BOM to the start of each LESS and CSS file.
|
||||
// This is a based on the copySync method from fs-extra (https://github.com/jprichardson/node-fs-extra/).
|
||||
|
||||
module.exports = function() {
|
||||
var path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
var BUF_LENGTH = 64 * 1024;
|
||||
var _buff = new Buffer(BUF_LENGTH);
|
||||
|
||||
function copyFolderWithBom(src, dest) {
|
||||
var stats = fs.lstatSync(src);
|
||||
var destFolder = path.dirname(dest);
|
||||
var destFolderExists = fs.existsSync(destFolder);
|
||||
var performCopy = false;
|
||||
|
||||
if (stats.isFile()) {
|
||||
if (!destFolderExists) {
|
||||
fs.mkdirSync(destFolder);
|
||||
}
|
||||
if (src.match(/\.(css|less)$/)) {
|
||||
copyFileAddingBomSync(src, dest);
|
||||
} else {
|
||||
copyFileSync(src, dest);
|
||||
}
|
||||
}
|
||||
else if (stats.isDirectory()) {
|
||||
if (!fs.existsSync(destFolder)) {
|
||||
fs.mkdirSync(destFolder);
|
||||
}
|
||||
if (!fs.existsSync(dest)) {
|
||||
fs.mkdirSync(dest);
|
||||
}
|
||||
fs.readdirSync(src).forEach(function(d) {
|
||||
if (d !== 'bom') {
|
||||
copyFolderWithBom(path.join(src, d), path.join(dest, d));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function copyFileAddingBomSync(srcFile, destFile) {
|
||||
var contents = fs.readFileSync(srcFile, { encoding: 'utf8' });
|
||||
if (!contents.length || contents.charCodeAt(0) !== 0xFEFF) {
|
||||
contents = '\ufeff' + contents;
|
||||
}
|
||||
fs.writeFileSync(destFile, contents, { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
function copyFileSync(srcFile, destFile) {
|
||||
var fdr = fs.openSync(srcFile, 'r')
|
||||
var stat = fs.fstatSync(fdr)
|
||||
var fdw = fs.openSync(destFile, 'w', stat.mode)
|
||||
var bytesRead = 1
|
||||
var pos = 0
|
||||
|
||||
while (bytesRead > 0) {
|
||||
bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos)
|
||||
fs.writeSync(fdw, _buff, 0, bytesRead)
|
||||
pos += bytesRead
|
||||
}
|
||||
|
||||
fs.closeSync(fdr)
|
||||
fs.closeSync(fdw)
|
||||
}
|
||||
|
||||
return {
|
||||
copyFolderWithBom: copyFolderWithBom
|
||||
};
|
||||
};
|
||||
@@ -80,3 +80,4 @@
|
||||
#output-block {
|
||||
comment: /* // Not commented out // */;
|
||||
}
|
||||
/*comment on last line*/
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
mixt: rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
#built-in .is-a {
|
||||
ruleset: true;
|
||||
color: true;
|
||||
color1: true;
|
||||
color2: true;
|
||||
|
||||
@@ -34,6 +34,14 @@ div#id.class[a=1][b=2].class:not(1) {
|
||||
.visible + .visible .sub {
|
||||
color: green;
|
||||
}
|
||||
@supports (something: else) {
|
||||
.class {
|
||||
something: else;
|
||||
}
|
||||
.nestedToo .class {
|
||||
something: else;
|
||||
}
|
||||
}
|
||||
.b {
|
||||
color: red;
|
||||
color: green;
|
||||
@@ -66,3 +74,20 @@ div#id.class[a=1][b=2].class:not(1) {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
.test {
|
||||
color: red;
|
||||
}
|
||||
.test:first-child {
|
||||
color: blue;
|
||||
}
|
||||
@keyframes some-name {
|
||||
property: value;
|
||||
}
|
||||
@supports (animation-name: test) {
|
||||
@keyframes some-name {
|
||||
property: value;
|
||||
}
|
||||
.selector {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,3 +43,9 @@
|
||||
.class .inner {
|
||||
test: 9;
|
||||
}
|
||||
.when-calling-nested-issue-2394 {
|
||||
width: auto !important;
|
||||
}
|
||||
.when-calling-nested-with-param-issue-2394 {
|
||||
width: 10px !important;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ p a span {
|
||||
.bloodred {
|
||||
color: green;
|
||||
}
|
||||
#blood.blood.red.black {
|
||||
#blood.blood.red.black:blood {
|
||||
color: black;
|
||||
}
|
||||
:nth-child(3) {
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
}
|
||||
#data-uri {
|
||||
uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==");
|
||||
background-image: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=="), url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==");
|
||||
uri-fragment: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==#fragment");
|
||||
}
|
||||
#data-uri-guess {
|
||||
|
||||
@@ -4,12 +4,11 @@ var lessTest = require("./less-test"),
|
||||
stylize = require('../lib/less-node/lessc-helper').stylize;
|
||||
|
||||
function getErrorPathReplacementFunction(dir) {
|
||||
return function(input) {
|
||||
return input.replace(
|
||||
/\{path\}/g, path.join(process.cwd(), "/test/less/" + dir + "/"))
|
||||
.replace(/\{node\}/g, "")
|
||||
.replace(/\{\/node\}/g, "")
|
||||
.replace(/\{pathrel\}/g, path.join("test", "less", dir + "/"))
|
||||
return function(input, baseDir) {
|
||||
return input.replace(/\{path\}/g, path.join(process.cwd(), baseDir, dir + "/"))
|
||||
.replace(/\{node\}/g, "")
|
||||
.replace(/\{\/node\}/g, "")
|
||||
.replace(/\{pathrel\}/g, path.join(baseDir, dir + "/"))
|
||||
.replace(/\{pathhref\}/g, "")
|
||||
.replace(/\{404status\}/g, "")
|
||||
.replace(/\r\n/g, '\n');
|
||||
@@ -17,6 +16,7 @@ function getErrorPathReplacementFunction(dir) {
|
||||
}
|
||||
|
||||
console.log("\n" + stylize("Less", 'underline') + "\n");
|
||||
lessTester.prepBomTest();
|
||||
lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true});
|
||||
lessTester.runTestSet({strictMath: true, strictUnits: true}, "errors/",
|
||||
lessTester.testErrors, null, getErrorPathReplacementFunction("errors"));
|
||||
@@ -34,18 +34,18 @@ lessTester.runTestSet({strictMath: true, strictUnits: true}, "strict-units/");
|
||||
lessTester.runTestSet({}, "legacy/");
|
||||
lessTester.runTestSet({strictMath: true, strictUnits: true, sourceMap: true, globalVars: true }, "sourcemaps/",
|
||||
lessTester.testSourcemap, null, null,
|
||||
function(filename, type) {
|
||||
function(filename, type, baseFolder) {
|
||||
if (type === "vars") {
|
||||
return path.join('test/less/', filename) + '.json';
|
||||
return path.join(baseFolder, filename) + '.json';
|
||||
}
|
||||
return path.join('test/sourcemaps', filename) + '.json';
|
||||
});
|
||||
lessTester.runTestSet({globalVars: true, banner: "/**\n * Test\n */\n"}, "globalVars/",
|
||||
null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
|
||||
null, null, null, function(name, type, baseFolder) { return path.join(baseFolder, name) + '.json'; });
|
||||
lessTester.runTestSet({modifyVars: true}, "modifyVars/",
|
||||
null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
|
||||
null, null, null, function(name, type, baseFolder) { return path.join(baseFolder, name) + '.json'; });
|
||||
lessTester.runTestSet({urlArgs: '424242'}, "url-args/");
|
||||
lessTester.runTestSet({paths: ['test/data/','test/less/import/']}, "include-path/");
|
||||
lessTester.runTestSet({paths: ['test/data/', 'test/less/import/']}, "include-path/");
|
||||
lessTester.testSyncronous({syncImport: true}, "import");
|
||||
lessTester.testSyncronous({syncImport: true}, "css");
|
||||
lessTester.testNoOptions();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
module.exports = function() {
|
||||
var path = require('path'),
|
||||
fs = require('fs');
|
||||
copyBom = require('./copy-bom')();
|
||||
|
||||
var less = require('../lib/less-node');
|
||||
var stylize = require('../lib/less-node/lessc-helper').stylize;
|
||||
@@ -10,10 +11,13 @@ module.exports = function() {
|
||||
var globals = Object.keys(global);
|
||||
|
||||
var oneTestOnly = process.argv[2],
|
||||
isFinished = false;
|
||||
isFinished = false;
|
||||
|
||||
var isVerbose = process.env.npm_config_loglevel === 'verbose';
|
||||
|
||||
var normalFolder = 'test/less';
|
||||
var bomFolder = 'test/less-bom';
|
||||
|
||||
less.logger.addListener({
|
||||
info: function(msg) {
|
||||
if (isVerbose) {
|
||||
@@ -21,10 +25,10 @@ module.exports = function() {
|
||||
}
|
||||
},
|
||||
warn: function(msg) {
|
||||
process.stdout.write(msg + "\n");
|
||||
process.stdout.write(msg + "\n");
|
||||
},
|
||||
error: function(msg) {
|
||||
process.stdout.write(msg + "\n");
|
||||
process.stdout.write(msg + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,21 +36,21 @@ module.exports = function() {
|
||||
queueRunning = false;
|
||||
function queue(func) {
|
||||
if (queueRunning) {
|
||||
//console.log("adding to queue");
|
||||
//console.log("adding to queue");
|
||||
queueList.push(func);
|
||||
} else {
|
||||
//console.log("first in queue - starting");
|
||||
//console.log("first in queue - starting");
|
||||
queueRunning = true;
|
||||
func();
|
||||
}
|
||||
}
|
||||
function release() {
|
||||
if (queueList.length) {
|
||||
//console.log("running next in queue");
|
||||
//console.log("running next in queue");
|
||||
var func = queueList.shift();
|
||||
setTimeout(func, 0);
|
||||
setTimeout(func, 0);
|
||||
} else {
|
||||
//console.log("stopping queue");
|
||||
//console.log("stopping queue");
|
||||
queueRunning = false;
|
||||
}
|
||||
}
|
||||
@@ -67,9 +71,9 @@ module.exports = function() {
|
||||
}
|
||||
});
|
||||
|
||||
function testSourcemap(name, err, compiledLess, doReplacements, sourcemap) {
|
||||
function testSourcemap(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
|
||||
process.stdout.write("- " + name + ": ");
|
||||
process.stdout.write("- " + path.join(baseFolder, name) + ": ");
|
||||
if (sourcemap === expectedSourcemap) {
|
||||
ok('OK');
|
||||
} else if (err) {
|
||||
@@ -84,10 +88,10 @@ module.exports = function() {
|
||||
});
|
||||
}
|
||||
|
||||
function testErrors(name, err, compiledLess, doReplacements) {
|
||||
fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) {
|
||||
process.stdout.write("- " + name + ": ");
|
||||
expectedErr = doReplacements(expectedErr, 'test/less/errors/');
|
||||
function testErrors(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
fs.readFile(path.join(baseFolder, name) + '.txt', 'utf8', function (e, expectedErr) {
|
||||
process.stdout.write("- " + path.join(baseFolder, name) + ": ");
|
||||
expectedErr = doReplacements(expectedErr, baseFolder);
|
||||
if (!err) {
|
||||
if (compiledLess) {
|
||||
fail("No Error", 'red');
|
||||
@@ -108,8 +112,8 @@ module.exports = function() {
|
||||
function globalReplacements(input, directory) {
|
||||
var p = path.join(process.cwd(), directory),
|
||||
pathimport = path.join(process.cwd(), directory + "import/"),
|
||||
pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }),
|
||||
pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); });
|
||||
pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a == '\\' ? '\/' : a); }),
|
||||
pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a == '\\' ? '\/' : a); });
|
||||
|
||||
return input.replace(/\{path\}/g, p)
|
||||
.replace(/\{pathesc\}/g, pathesc)
|
||||
@@ -125,13 +129,13 @@ module.exports = function() {
|
||||
}
|
||||
|
||||
function testSyncronous(options, filenameNoExtension) {
|
||||
if (oneTestOnly && ("Test Sync " + filenameNoExtension) !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
totalTests++;
|
||||
if (oneTestOnly && ("Test Sync " + filenameNoExtension) !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
totalTests++;
|
||||
queue(function() {
|
||||
var isSync = true;
|
||||
toCSS(options, path.join('test/less/', filenameNoExtension + ".less"), function (err, result) {
|
||||
toCSS(options, path.join(normalFolder, filenameNoExtension + ".less"), function (err, result) {
|
||||
process.stdout.write("- Test Sync " + filenameNoExtension + ": ");
|
||||
|
||||
if (isSync) {
|
||||
@@ -139,13 +143,27 @@ module.exports = function() {
|
||||
} else {
|
||||
fail("Not Sync");
|
||||
}
|
||||
release();
|
||||
release();
|
||||
});
|
||||
isSync = false;
|
||||
});
|
||||
}
|
||||
|
||||
function prepBomTest() {
|
||||
copyBom.copyFolderWithBom(normalFolder, bomFolder);
|
||||
}
|
||||
|
||||
function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
var options2 = options ? JSON.parse(JSON.stringify(options)) : {};
|
||||
runTestSetInternal(normalFolder, options, foldername, verifyFunction, nameModifier, doReplacements, getFilename);
|
||||
runTestSetInternal(bomFolder, options2, foldername, verifyFunction, nameModifier, doReplacements, getFilename);
|
||||
}
|
||||
|
||||
function runTestSetNormalOnly(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
runTestSetInternal(normalFolder, options, foldername, verifyFunction, nameModifier, doReplacements, getFilename);
|
||||
}
|
||||
|
||||
function runTestSetInternal(baseFolder, options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
foldername = foldername || "";
|
||||
|
||||
if(!doReplacements) {
|
||||
@@ -156,7 +174,7 @@ module.exports = function() {
|
||||
return foldername + path.basename(file, '.less');
|
||||
}
|
||||
|
||||
fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) {
|
||||
fs.readdirSync(path.join(baseFolder, foldername)).forEach(function (file) {
|
||||
if (! /\.less/.test(file)) { return; }
|
||||
|
||||
var name = getBasename(file);
|
||||
@@ -169,32 +187,32 @@ module.exports = function() {
|
||||
|
||||
if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = name + ".css";
|
||||
options.sourceMapBasepath = path.join(process.cwd(), "test/less");
|
||||
options.sourceMapBasepath = path.join(process.cwd(), baseFolder);
|
||||
options.sourceMapRootpath = "testweb/";
|
||||
// TODO separate options?
|
||||
options.sourceMap = options;
|
||||
}
|
||||
|
||||
options.getVars = function(file) {
|
||||
return JSON.parse(fs.readFileSync(getFilename(getBasename(file), 'vars'), 'utf8'));
|
||||
return JSON.parse(fs.readFileSync(getFilename(getBasename(file), 'vars', baseFolder), 'utf8'));
|
||||
};
|
||||
|
||||
var doubleCallCheck = false;
|
||||
var doubleCallCheck = false;
|
||||
queue(function() {
|
||||
toCSS(options, path.join('test/less/', foldername + file), function (err, result) {
|
||||
if (doubleCallCheck) {
|
||||
totalTests++;
|
||||
fail("less is calling back twice");
|
||||
process.stdout.write(doubleCallCheck + "\n");
|
||||
process.stdout.write((new Error()).stack + "\n");
|
||||
return;
|
||||
}
|
||||
doubleCallCheck = (new Error()).stack;
|
||||
toCSS(options, path.join(baseFolder, foldername + file), function (err, result) {
|
||||
if (doubleCallCheck) {
|
||||
totalTests++;
|
||||
fail("less is calling back twice");
|
||||
process.stdout.write(doubleCallCheck + "\n");
|
||||
process.stdout.write((new Error()).stack + "\n");
|
||||
return;
|
||||
}
|
||||
doubleCallCheck = (new Error()).stack;
|
||||
|
||||
if (verifyFunction) {
|
||||
var verificationResult = verifyFunction(name, err, result && result.css, doReplacements, result && result.map);
|
||||
release();
|
||||
return verificationResult;
|
||||
var verificationResult = verifyFunction(name, err, result && result.css, doReplacements, result && result.map, baseFolder);
|
||||
release();
|
||||
return verificationResult;
|
||||
}
|
||||
if (err) {
|
||||
fail("ERROR: " + (err && err.message));
|
||||
@@ -208,9 +226,9 @@ module.exports = function() {
|
||||
var css_name = name;
|
||||
if(nameModifier) { css_name = nameModifier(name); }
|
||||
fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) {
|
||||
process.stdout.write("- " + css_name + ": ");
|
||||
process.stdout.write("- " + path.join(baseFolder, css_name) + ": ");
|
||||
|
||||
css = css && doReplacements(css, 'test/less/' + foldername);
|
||||
css = css && doReplacements(css, path.join(baseFolder, foldername));
|
||||
if (result.css === css) { ok('OK'); }
|
||||
else {
|
||||
difference("FAIL", css, result.css);
|
||||
@@ -225,10 +243,10 @@ module.exports = function() {
|
||||
function diff(left, right) {
|
||||
require('diff').diffLines(left, right).forEach(function(item) {
|
||||
if(item.added || item.removed) {
|
||||
var text = item.value.replace("\n", String.fromCharCode(182) + "\n");
|
||||
var text = item.value.replace("\n", String.fromCharCode(182) + "\n").replace('\ufeff', '[[BOM]]');
|
||||
process.stdout.write(stylize(text, item.added ? 'green' : 'red'));
|
||||
} else {
|
||||
process.stdout.write(item.value);
|
||||
process.stdout.write(item.value.replace('\ufeff', '[[BOM]]'));
|
||||
}
|
||||
});
|
||||
process.stdout.write("\n");
|
||||
@@ -253,16 +271,16 @@ module.exports = function() {
|
||||
passedTests++;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function finished() {
|
||||
isFinished = true;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function finished() {
|
||||
isFinished = true;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function endTest() {
|
||||
if (isFinished && ((failedTests + passedTests) >= totalTests)) {
|
||||
var leaked = checkGlobalLeaks();
|
||||
|
||||
var leaked = checkGlobalLeaks();
|
||||
|
||||
process.stdout.write("\n");
|
||||
if (failedTests > 0) {
|
||||
process.stdout.write(failedTests + stylize(" Failed", "red") + ", " + passedTests + " passed\n");
|
||||
@@ -289,8 +307,7 @@ module.exports = function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function toCSS(options, path, callback) {
|
||||
function toCSS(options, path, callback) {
|
||||
options = options || {};
|
||||
var str = fs.readFileSync(path, 'utf8'), addPath = require('path').dirname(path);
|
||||
|
||||
@@ -311,9 +328,9 @@ module.exports = function() {
|
||||
}
|
||||
|
||||
function testNoOptions() {
|
||||
if (oneTestOnly && "Integration" !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
if (oneTestOnly && "Integration" !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
totalTests++;
|
||||
try {
|
||||
process.stdout.write("- Integration - creating parser without options: ");
|
||||
@@ -327,10 +344,12 @@ module.exports = function() {
|
||||
|
||||
return {
|
||||
runTestSet: runTestSet,
|
||||
runTestSetNormalOnly: runTestSetNormalOnly,
|
||||
testSyncronous: testSyncronous,
|
||||
testErrors: testErrors,
|
||||
testSourcemap: testSourcemap,
|
||||
testNoOptions: testNoOptions,
|
||||
finished: finished
|
||||
prepBomTest: prepBomTest,
|
||||
finished: finished
|
||||
};
|
||||
};
|
||||
|
||||
@@ -99,3 +99,4 @@
|
||||
/*by block */
|
||||
@string_w_comment: ~"/* // Not commented out // */";
|
||||
#output-block { comment: @string_w_comment; }
|
||||
/*comment on last line*/
|
||||
@@ -137,6 +137,10 @@
|
||||
mixt: mix(#ff0000, transparent);
|
||||
|
||||
.is-a {
|
||||
@rules: {
|
||||
color: red;
|
||||
};
|
||||
ruleset: isruleset(@rules);
|
||||
color: iscolor(#ddd);
|
||||
color1: iscolor(red);
|
||||
color2: iscolor(rgb(0, 0, 0));
|
||||
|
||||
@@ -18,4 +18,6 @@
|
||||
}
|
||||
|
||||
.class:extend(.class all) {
|
||||
}
|
||||
}
|
||||
.mixin-with-nested-selectors();
|
||||
.mixin-with-directives(some-name);
|
||||
2
test/less/import.less
vendored
2
test/less/import.less
vendored
@@ -2,6 +2,8 @@
|
||||
|
||||
@import url(/absolute/something.css) screen and (color) and (max-width: 600px);
|
||||
|
||||
@import (optional) "file-does-not-exist.does-not-exist";
|
||||
|
||||
@var: 100px;
|
||||
@import url("//ha.com/file.css") (min-width:@var);
|
||||
|
||||
|
||||
@@ -48,4 +48,42 @@
|
||||
@media (max-size: @max-size) {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
//https://github.com/less/less.js/issues/2359
|
||||
@supports (something: else) {
|
||||
.class {
|
||||
something: else;
|
||||
}
|
||||
.nestedToo {
|
||||
.class {
|
||||
something: else;
|
||||
}
|
||||
}
|
||||
.invisible {
|
||||
something: else;
|
||||
}
|
||||
}
|
||||
//https://github.com/less/less.js/issues/1979
|
||||
.mixin-with-nested-selectors() {
|
||||
.test {
|
||||
color: red;
|
||||
&:first-child {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mixin-with-directives(@keyframeName) {
|
||||
@keyframes @keyframeName {
|
||||
@rules1();
|
||||
}
|
||||
@supports (animation-name: test) {
|
||||
@keyframes @keyframeName {
|
||||
@rules2();
|
||||
}
|
||||
.selector {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
@rules1: {property: value;};
|
||||
@rules2: {property: value;};
|
||||
}
|
||||
@@ -23,3 +23,15 @@
|
||||
.mixin !important;
|
||||
.mixin(9);
|
||||
}
|
||||
.size(@aaa: auto) {
|
||||
.set-width(@aaa) {
|
||||
width: @aaa;
|
||||
}
|
||||
.set-width(@aaa);
|
||||
}
|
||||
.when-calling-nested-issue-2394 {
|
||||
.size() !important;
|
||||
}
|
||||
.when-calling-nested-with-param-issue-2394 {
|
||||
.size(10px) !important;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ a {
|
||||
color: green;
|
||||
}
|
||||
.red {
|
||||
#@{theme}.@{theme}&.black {
|
||||
#@{theme}.@{theme}&.black:@{theme} {
|
||||
color:black;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
|
||||
#data-uri {
|
||||
uri: data-uri('image/jpeg;base64', '../data/image.jpg');
|
||||
@var: replace('../data/replace.jpg', "replace", "image");
|
||||
background-image: data-uri(@var), data-uri(replace('../data/image.filext', "filext", "jpg"));
|
||||
|
||||
uri-fragment: data-uri('image/jpeg;base64', '../data/image.jpg#fragment');
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ var options = {
|
||||
}
|
||||
|
||||
less.render(input, options, function (err, result) {
|
||||
if (err) console.log(err);
|
||||
if (result.css === expectedCss) {
|
||||
console.log("PASS")
|
||||
} else {
|
||||
console.log("FAIL")
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
})
|
||||
if (result.css === expectedCss) {
|
||||
console.log("PASS");
|
||||
} else {
|
||||
console.log("FAIL");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user