mirror of
https://github.com/less/less.js.git
synced 2026-05-01 03:00:22 -04:00
Merge branch '3.x' into dev/3.x-work
This commit is contained in:
@@ -72,6 +72,7 @@
|
||||
"all"
|
||||
],
|
||||
"space-infix-ops": 2,
|
||||
"spaced-comment": 1,
|
||||
"space-before-blocks": [
|
||||
2,
|
||||
"always"
|
||||
|
||||
@@ -3,6 +3,7 @@ cache:
|
||||
directories:
|
||||
- travis-phantomjs
|
||||
node_js:
|
||||
- "8"
|
||||
- "6"
|
||||
- "4"
|
||||
- "0.12"
|
||||
|
||||
@@ -122,14 +122,15 @@ module.exports = function (grunt) {
|
||||
var pass = process.env.SAUCE_ACCESS_KEY;
|
||||
|
||||
git.short(function(hash) {
|
||||
require('request').put({
|
||||
require('phin')({
|
||||
method: 'PUT',
|
||||
url: ['https://saucelabs.com/rest/v1', user, 'jobs', result.job_id].join('/'),
|
||||
auth: { user: user, pass: pass },
|
||||
json: {
|
||||
data: {
|
||||
passed: result.passed,
|
||||
build: 'build-' + hash
|
||||
}
|
||||
}, function (error, response, body) {
|
||||
}, function (error, response) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
callback(error);
|
||||
@@ -519,7 +520,7 @@ module.exports = function (grunt) {
|
||||
grunt.registerTask('test', testTasks);
|
||||
|
||||
// Run all tests
|
||||
grunt.registerTask('quicktest', testTasks.slice(0, testTasks.length - 1));
|
||||
grunt.registerTask('quicktest', testTasks.slice(0, -1));
|
||||
|
||||
// generate a good test environment for testing sourcemaps
|
||||
grunt.registerTask('sourcemap-test', [
|
||||
|
||||
10
README.md
10
README.md
@@ -1,6 +1,6 @@
|
||||
[](http://badge.fury.io/js/less) [](https://travis-ci.org/less/less.js)
|
||||
[](https://david-dm.org/less/less.js) [](https://david-dm.org/less/less.js#info=devDependencies) [](https://david-dm.org/less/less.js#info=optionalDependencies)
|
||||
[](https://saucelabs.com/u/less) [](https://ci.appveyor.com/project/lukeapage/less-js/branch/3.x)
|
||||
[](http://badge.fury.io/js/less) [](https://travis-ci.org/less/less.js) [](https://ci.appveyor.com/project/lukeapage/less-js/branch/3.x) [](https://david-dm.org/less/less.js) [](https://david-dm.org/less/less.js#info=devDependencies) [](https://david-dm.org/less/less.js#info=optionalDependencies) [](https://twitter.com/lesstocss) [](https://gitter.im/less/less.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <sup>Chat with Less.js users</sup>
|
||||
|
||||
[](https://saucelabs.com/u/less)
|
||||
|
||||
# [Less.js](http://lesscss.org)
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
This is the JavaScript, official, stable version of Less.
|
||||
|
||||
###### :point_right: [](https://gitter.im/less/less.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <sup>Chat with Less.js users</sup>
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -51,6 +49,6 @@ Copyright (c) 2009-2016 [Alexis Sellier](http://cloudhead.io) & The Core Less Te
|
||||
Licensed under the [Apache License](LICENSE).
|
||||
|
||||
|
||||
[so]: http://stackoverflow.com/questions/tagged/twitter-bootstrap+less "StackOverflow.com"
|
||||
[so]: http://stackoverflow.com/questions/tagged/less "StackOverflow.com"
|
||||
[issues]: https://github.com/less/less.js/issues "GitHub Issues for Less.js"
|
||||
[download]: https://github.com/less/less.js/zipball/master "Download Less.js"
|
||||
|
||||
@@ -5,6 +5,7 @@ environment:
|
||||
- nodejs_version: "0.12"
|
||||
- nodejs_version: "4"
|
||||
- nodejs_version: "6"
|
||||
- nodejs_version: "8"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
|
||||
14
bin/lessc
14
bin/lessc
@@ -19,22 +19,10 @@ var less = require('../lib/less-node'),
|
||||
args = process.argv.slice(1),
|
||||
silent = false,
|
||||
verbose = false,
|
||||
options = require('../lib/less/default-options')();
|
||||
options = less.options;
|
||||
|
||||
options.plugins = plugins;
|
||||
|
||||
if (less.options) {
|
||||
for (var i = 0, keys = Object.keys(options); i < keys.length; i++) {
|
||||
if (!less.options[keys[i]]) {
|
||||
less.options[keys[i]] = options[keys[i]];
|
||||
}
|
||||
}
|
||||
options = less.options;
|
||||
}
|
||||
else {
|
||||
less.options = options;
|
||||
}
|
||||
|
||||
var sourceMapOptions = {};
|
||||
var continueProcessing = true;
|
||||
|
||||
|
||||
4
lib/less-browser/bootstrap.js
vendored
4
lib/less-browser/bootstrap.js
vendored
@@ -3,14 +3,14 @@
|
||||
* used in the browser distributed version of less
|
||||
* to kick-start less using the browser api
|
||||
*/
|
||||
/*global window, document */
|
||||
/* global window, document */
|
||||
|
||||
// TODO - consider switching this out for a recommendation for this polyfill?
|
||||
// <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
|
||||
// Browsers have good Promise support
|
||||
require("promise/polyfill");
|
||||
|
||||
var options = require('../less/default-options');
|
||||
var options = require('../less/default-options')();
|
||||
|
||||
if (window.less) {
|
||||
for (key in window.less) {
|
||||
|
||||
@@ -18,7 +18,7 @@ module.exports = function(window, options, logger) {
|
||||
cache.setItem(path + ':vars', JSON.stringify(modifyVars));
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO - could do with adding more robust error handling
|
||||
// TODO - could do with adding more robust error handling
|
||||
logger.error('failed to save "' + path + '" to local storage for caching.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ module.exports = function(window, less, options) {
|
||||
}
|
||||
|
||||
function removeErrorConsole(path) {
|
||||
//no action
|
||||
// no action
|
||||
}
|
||||
|
||||
function removeError(path) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*global window, XMLHttpRequest */
|
||||
/* global window, XMLHttpRequest */
|
||||
|
||||
module.exports = function(options, logger) {
|
||||
|
||||
@@ -6,7 +6,7 @@ module.exports = function(options, logger) {
|
||||
|
||||
var fileCache = {};
|
||||
|
||||
//TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
|
||||
// TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
|
||||
var FileManager = function() {
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ module.exports = function(window, options) {
|
||||
var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
|
||||
require('./image-size')(less.environment);
|
||||
|
||||
//Setup user functions - Deprecate?
|
||||
// Setup user functions - Deprecate?
|
||||
if (options.functions) {
|
||||
less.functions.functionRegistry.addMultiple(options.functions);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ module.exports = function(window, options) {
|
||||
var lessText = style.innerHTML || '';
|
||||
instanceOptions.filename = document.location.href.replace(/#.*$/, '');
|
||||
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
// use closure to store current style
|
||||
less.render(lessText, instanceOptions,
|
||||
bind(function(style, e, result) {
|
||||
@@ -110,7 +110,7 @@ module.exports = function(window, options) {
|
||||
|
||||
}
|
||||
|
||||
//TODO add tests around how this behaves when reloading
|
||||
// TODO add tests around how this behaves when reloading
|
||||
errors.remove(path);
|
||||
|
||||
instanceOptions.rootFileInfo = newFileInfo;
|
||||
|
||||
@@ -13,7 +13,9 @@ less.PluginLoader = require("./plugin-loader");
|
||||
less.fs = require("./fs");
|
||||
less.FileManager = FileManager;
|
||||
less.UrlFileManager = UrlFileManager;
|
||||
less.options = require('../less/default-options');
|
||||
|
||||
// Set up options
|
||||
less.options = require('../less/default-options')();
|
||||
less.options.paths = [
|
||||
path.join(process.cwd(), "node_modules")
|
||||
];
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// helper functions for lessc
|
||||
var lessc_helper = {
|
||||
|
||||
//Stylize a string
|
||||
// Stylize a string
|
||||
stylize : function(str, style) {
|
||||
var styles = {
|
||||
'reset' : [0, 0],
|
||||
@@ -19,7 +19,7 @@ var lessc_helper = {
|
||||
'\x1b[' + styles[style][1] + 'm';
|
||||
},
|
||||
|
||||
//Print command line options
|
||||
// Print command line options
|
||||
printUsage: function() {
|
||||
console.log("usage: lessc [option option=parameter ...] <source> [destination]");
|
||||
console.log("");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* jshint rhino:true, unused: false */
|
||||
/* jscs:disable validateIndentation */
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
/* global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
@@ -9,7 +8,7 @@ function formatError(ctx, options) {
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
@@ -211,8 +210,8 @@ function writeFile(filename, content) {
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
@@ -255,7 +254,7 @@ function writeFile(filename, content) {
|
||||
.split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
@@ -336,20 +335,20 @@ function writeFile(filename, content) {
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
@@ -367,24 +366,25 @@ function writeFile(filename, content) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
// require('../lib/less/lessc_helper').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; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
/*
|
||||
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.depends) {
|
||||
if (!outputbase) {
|
||||
|
||||
@@ -40,17 +40,17 @@ 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
|
||||
'strictUnits', // whether units need to evaluate correctly
|
||||
'sourceMap', // whether to output a source map
|
||||
'importMultiple', // whether we are currently importing multiple copies
|
||||
'urlArgs', // whether to add args into url tokens
|
||||
'javascriptEnabled',// option - whether Inline JavaScript is enabled. if undefined, defaults to false
|
||||
'pluginManager', // Used as the plugin manager for the session
|
||||
'importantScope' // used to bubble up !important statements
|
||||
'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
|
||||
'strictUnits', // whether units need to evaluate correctly
|
||||
'sourceMap', // whether to output a source map
|
||||
'importMultiple', // whether we are currently importing multiple copies
|
||||
'urlArgs', // whether to add args into url tokens
|
||||
'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false
|
||||
'pluginManager', // Used as the plugin manager for the session
|
||||
'importantScope' // used to bubble up !important statements
|
||||
];
|
||||
|
||||
contexts.Eval = function(options, frames) {
|
||||
@@ -108,4 +108,4 @@ contexts.Eval.prototype.normalizePath = function( path ) {
|
||||
return path.join("/");
|
||||
};
|
||||
|
||||
//todo - do the same for the toCSS ?
|
||||
// todo - do the same for the toCSS ?
|
||||
|
||||
15
lib/less/functions/boolean.js
Normal file
15
lib/less/functions/boolean.js
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
var functionRegistry = require("./function-registry"),
|
||||
Anonymous = require("../tree/anonymous"),
|
||||
Keyword = require("../tree/keyword");
|
||||
|
||||
functionRegistry.addMultiple({
|
||||
boolean: function(condition) {
|
||||
return condition ? Keyword.True : Keyword.False;
|
||||
},
|
||||
|
||||
'if': function(condition, trueValue, falseValue) {
|
||||
return condition ? trueValue
|
||||
: (falseValue || new Anonymous);
|
||||
}
|
||||
});
|
||||
@@ -278,7 +278,7 @@ colorFunctions = {
|
||||
if (typeof dark === 'undefined') {
|
||||
dark = colorFunctions.rgba(0, 0, 0, 1.0);
|
||||
}
|
||||
//Figure out which is actually light and dark!
|
||||
// Figure out which is actually light and dark:
|
||||
if (dark.luma() > light.luma()) {
|
||||
var t = light;
|
||||
light = dark;
|
||||
|
||||
@@ -7,7 +7,7 @@ function makeRegistry( base ) {
|
||||
name = name.toLowerCase();
|
||||
|
||||
if (this._data.hasOwnProperty(name)) {
|
||||
//TODO warn
|
||||
// TODO warn
|
||||
}
|
||||
this._data[name] = func;
|
||||
},
|
||||
|
||||
@@ -4,7 +4,8 @@ module.exports = function(environment) {
|
||||
functionCaller: require("./function-caller")
|
||||
};
|
||||
|
||||
//register functions
|
||||
// register functions
|
||||
require("./boolean");
|
||||
require("./default");
|
||||
require("./color");
|
||||
require("./color-blending");
|
||||
|
||||
@@ -19,12 +19,12 @@ functionRegistry.addMultiple({
|
||||
result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);
|
||||
return new Quoted(string.quote || '', result, string.escaped);
|
||||
},
|
||||
'%': function (string /* arg, arg, ...*/) {
|
||||
'%': function (string /* arg, arg, ... */) {
|
||||
var args = Array.prototype.slice.call(arguments, 1),
|
||||
result = string.value;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
result = result.replace(/%[sda]/i, function(token) {
|
||||
var value = ((args[i].type === "Quoted") &&
|
||||
token.match(/s/i)) ? args[i].value : args[i].toCSS();
|
||||
|
||||
@@ -37,7 +37,7 @@ module.exports = function(environment, fileManagers) {
|
||||
};
|
||||
var t, api = Object.create(initial);
|
||||
for (var n in initial.tree) {
|
||||
/*eslint guard-for-in: 0 */
|
||||
/* eslint guard-for-in: 0 */
|
||||
t = initial.tree[n];
|
||||
if (typeof t === "function") {
|
||||
api[n] = ctor(t);
|
||||
@@ -45,7 +45,7 @@ module.exports = function(environment, fileManagers) {
|
||||
else {
|
||||
api[n] = Object.create(null);
|
||||
for (var o in t) {
|
||||
/*eslint guard-for-in: 0 */
|
||||
/* eslint guard-for-in: 0 */
|
||||
api[n][o] = ctor(t[o]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
var chunker = require('./chunker');
|
||||
|
||||
module.exports = function() {
|
||||
var input, // LeSS input string
|
||||
var input, // Less input string
|
||||
j, // current chunk
|
||||
saveStack = [], // holds state for backtracking
|
||||
furthest, // furthest index the parser has gone to
|
||||
furthestPossibleErrorMessage,// if this is furthest we got to, this is the probably cause
|
||||
furthestPossibleErrorMessage, // if this is furthest we got to, this is the probably cause
|
||||
chunks, // chunkified input
|
||||
current, // current chunk
|
||||
currentPos, // index of current chunk, in `input`
|
||||
@@ -209,7 +209,7 @@ module.exports = function() {
|
||||
|
||||
parserInput.peekNotNumeric = function() {
|
||||
var c = input.charCodeAt(parserInput.i);
|
||||
//Is the first char of the dimension 0-9, '.', '+' or '-'
|
||||
// Is the first char of the dimension 0-9, '.', '+' or '-'
|
||||
return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ var LessError = require('../less-error'),
|
||||
// Token matching is done with the `$` function, which either takes
|
||||
// a terminal string or regexp, or a non-terminal function to call.
|
||||
// It also takes care of moving all the indices forwards.
|
||||
//`
|
||||
//
|
||||
|
||||
var Parser = function Parser(context, imports, fileInfo) {
|
||||
var parsers,
|
||||
parserInput = getParserInput();
|
||||
@@ -314,7 +314,7 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
}
|
||||
|
||||
node = mixin.definition() || this.declaration() || this.ruleset() ||
|
||||
mixin.call() || this.rulesetCall() || this.entities.call() || this.atrule();
|
||||
mixin.call() || this.variableCall() || this.entities.call() || this.atrule();
|
||||
if (node) {
|
||||
root.push(node);
|
||||
} else {
|
||||
@@ -383,13 +383,10 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
//
|
||||
// rgb(255, 0, 255)
|
||||
//
|
||||
// We also try to catch IE's `alpha()`, but let the `alpha` parser
|
||||
// deal with the details.
|
||||
//
|
||||
// The arguments are parsed with the `entities.arguments` parser.
|
||||
//
|
||||
call: function () {
|
||||
var name, nameLC, args, alpha, index = parserInput.i;
|
||||
var name, args, func, index = parserInput.i;
|
||||
|
||||
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
||||
if (parserInput.peek(/^url\(/i)) {
|
||||
@@ -399,20 +396,22 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
parserInput.save();
|
||||
|
||||
name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/);
|
||||
if (!name) { parserInput.forget(); return; }
|
||||
if (!name) {
|
||||
parserInput.forget();
|
||||
return;
|
||||
}
|
||||
|
||||
name = name[1];
|
||||
nameLC = name.toLowerCase();
|
||||
|
||||
if (nameLC === 'alpha') {
|
||||
alpha = parsers.alpha();
|
||||
if (alpha) {
|
||||
func = this.customFuncCall(name);
|
||||
if (func) {
|
||||
args = func.parse();
|
||||
if (args && func.stop) {
|
||||
parserInput.forget();
|
||||
return alpha;
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
args = this.arguments();
|
||||
args = this.arguments(args);
|
||||
|
||||
if (!parserInput.$char(')')) {
|
||||
parserInput.restore("Could not parse call arguments or missing ')'");
|
||||
@@ -422,47 +421,72 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
parserInput.forget();
|
||||
return new(tree.Call)(name, args, index, fileInfo);
|
||||
},
|
||||
arguments: function () {
|
||||
var argsSemiColon = [], argsComma = [],
|
||||
expressions = [],
|
||||
isSemiColonSeparated, value, arg;
|
||||
|
||||
//
|
||||
// Parsing rules for functions with non-standard args, e.g.:
|
||||
//
|
||||
// boolean(not(2 > 1))
|
||||
//
|
||||
// This is a quick prototype, to be modified/improved when
|
||||
// more custom-parsed funcs come (e.g. `selector(...)`)
|
||||
//
|
||||
|
||||
customFuncCall: function (name) {
|
||||
/* Ideally the table is to be moved out of here for faster perf.,
|
||||
but it's quite tricky since it relies on all these `parsers`
|
||||
and `expect` available only here */
|
||||
return {
|
||||
alpha: f(parsers.ieAlpha, true),
|
||||
boolean: f(condition),
|
||||
'if': f(condition)
|
||||
}[name.toLowerCase()];
|
||||
|
||||
function f(parse, stop) {
|
||||
return {
|
||||
parse: parse, // parsing function
|
||||
stop: stop // when true - stop after parse() and return its result,
|
||||
// otherwise continue for plain args
|
||||
};
|
||||
}
|
||||
|
||||
function condition() {
|
||||
return [expect(parsers.condition, 'expected condition')];
|
||||
}
|
||||
},
|
||||
|
||||
arguments: function (prevArgs) {
|
||||
var argsComma = prevArgs || [],
|
||||
argsSemiColon = [],
|
||||
isSemiColonSeparated, value;
|
||||
|
||||
parserInput.save();
|
||||
|
||||
while (true) {
|
||||
if (prevArgs) {
|
||||
prevArgs = false;
|
||||
} else {
|
||||
value = parsers.detachedRuleset() || this.assignment() || parsers.expression();
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
|
||||
arg = parsers.detachedRuleset() || this.assignment() || parsers.expression();
|
||||
if (value.value && value.value.length == 1) {
|
||||
value = value.value[0];
|
||||
}
|
||||
|
||||
if (!arg) {
|
||||
break;
|
||||
argsComma.push(value);
|
||||
}
|
||||
|
||||
value = arg;
|
||||
|
||||
if (arg.value && arg.value.length == 1) {
|
||||
value = arg.value[0];
|
||||
}
|
||||
|
||||
if (value) {
|
||||
expressions.push(value);
|
||||
}
|
||||
|
||||
argsComma.push(value);
|
||||
|
||||
if (parserInput.$char(',')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parserInput.$char(';') || isSemiColonSeparated) {
|
||||
|
||||
isSemiColonSeparated = true;
|
||||
|
||||
if (expressions.length > 1) {
|
||||
value = new(tree.Value)(expressions);
|
||||
}
|
||||
value = (argsComma.length < 1) ? argsComma[0]
|
||||
: new tree.Value(argsComma);
|
||||
argsSemiColon.push(value);
|
||||
|
||||
expressions = [];
|
||||
argsComma = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,15 +711,17 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
},
|
||||
|
||||
//
|
||||
// The variable part of a variable definition. Used in the `rule` parser
|
||||
// Call a variable value
|
||||
//
|
||||
// @fink();
|
||||
// @fink()
|
||||
//
|
||||
rulesetCall: function () {
|
||||
variableCall: function () {
|
||||
var name;
|
||||
|
||||
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\(\s*\)\s*;/))) {
|
||||
return new tree.RulesetCall(name[1]);
|
||||
if (parserInput.currentChar() === '@'
|
||||
&& (name = parserInput.$re(/^(@[\w-]+)\(\s*\)/))
|
||||
&& parsers.end()) {
|
||||
return new tree.VariableCall(name[1]);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1017,17 +1043,18 @@ var Parser = function Parser(context, imports, fileInfo) {
|
||||
//
|
||||
// alpha(opacity=88)
|
||||
//
|
||||
alpha: function () {
|
||||
ieAlpha: function () {
|
||||
var value;
|
||||
|
||||
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
||||
if (!parserInput.$re(/^opacity=/i)) { return; }
|
||||
value = parserInput.$re(/^\d+/);
|
||||
if (!value) {
|
||||
value = expect(this.entities.variable, "Could not parse alpha");
|
||||
value = expect(parsers.entities.variable, "Could not parse alpha");
|
||||
value = '@{' + value.name.slice(1) + '}';
|
||||
}
|
||||
expectChar(')');
|
||||
return new(tree.Alpha)(value);
|
||||
return new tree.Quoted('', 'alpha(opacity=' + value + ')');
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
@@ -47,7 +47,7 @@ module.exports = function (environment) {
|
||||
|
||||
SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
|
||||
|
||||
//ignore adding empty strings
|
||||
// ignore adding empty strings
|
||||
if (!chunk) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
var Node = require("./node");
|
||||
|
||||
var Alpha = function (val) {
|
||||
this.value = val;
|
||||
};
|
||||
Alpha.prototype = new Node();
|
||||
Alpha.prototype.type = "Alpha";
|
||||
|
||||
Alpha.prototype.accept = function (visitor) {
|
||||
this.value = visitor.visit(this.value);
|
||||
};
|
||||
Alpha.prototype.eval = function (context) {
|
||||
if (this.value.eval) { return new Alpha(this.value.eval(context)); }
|
||||
return this;
|
||||
};
|
||||
Alpha.prototype.genCSS = function (context, output) {
|
||||
output.add("alpha(opacity=");
|
||||
|
||||
if (this.value.genCSS) {
|
||||
this.value.genCSS(context, output);
|
||||
} else {
|
||||
output.add(this.value);
|
||||
}
|
||||
|
||||
output.add(")");
|
||||
};
|
||||
|
||||
module.exports = Alpha;
|
||||
@@ -61,11 +61,11 @@ AtRule.prototype.genCSS = function (context, output) {
|
||||
AtRule.prototype.eval = function (context) {
|
||||
var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
|
||||
|
||||
//media stored inside other atrule should not bubble over it
|
||||
//backpup media bubbling information
|
||||
// media stored inside other atrule should not bubble over it
|
||||
// backpup media bubbling information
|
||||
mediaPathBackup = context.mediaPath;
|
||||
mediaBlocksBackup = context.mediaBlocks;
|
||||
//deleted media bubbling information
|
||||
// deleted media bubbling information
|
||||
context.mediaPath = [];
|
||||
context.mediaBlocks = [];
|
||||
|
||||
@@ -77,7 +77,7 @@ AtRule.prototype.eval = function (context) {
|
||||
rules = [rules[0].eval(context)];
|
||||
rules[0].root = true;
|
||||
}
|
||||
//restore media bubbling information
|
||||
// restore media bubbling information
|
||||
context.mediaPath = mediaPathBackup;
|
||||
context.mediaBlocks = mediaBlocksBackup;
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ Color.prototype.toHSL = function () {
|
||||
}
|
||||
return { h: h * 360, s: s, l: l, a: a };
|
||||
};
|
||||
//Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
|
||||
// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
|
||||
Color.prototype.toHSV = function () {
|
||||
var r = this.rgb[0] / 255,
|
||||
g = this.rgb[1] / 255,
|
||||
|
||||
@@ -61,7 +61,7 @@ Dimension.prototype.genCSS = function (context, output) {
|
||||
// we default to the first Dimension's unit,
|
||||
// so `1px + 2` will yield `3px`.
|
||||
Dimension.prototype.operate = function (context, op, other) {
|
||||
/*jshint noempty:false */
|
||||
/* jshint noempty:false */
|
||||
var value = this._operate(context, op, this.value, other.value),
|
||||
unit = this.unit.clone();
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Extend.prototype.eval = function (context) {
|
||||
Extend.prototype.clone = function (context) {
|
||||
return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());
|
||||
};
|
||||
//it concatenates (joins) all selectors in selector array
|
||||
// it concatenates (joins) all selectors in selector array
|
||||
Extend.prototype.findSelfSelectors = function (selectors) {
|
||||
var selfElements = [],
|
||||
i,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var tree = Object.create(null);
|
||||
|
||||
tree.Node = require('./node');
|
||||
tree.Alpha = require('./alpha');
|
||||
tree.Color = require('./color');
|
||||
tree.AtRule = require('./atrule');
|
||||
// Backwards compatibility
|
||||
@@ -41,6 +40,6 @@ tree.Media = require('./media');
|
||||
tree.UnicodeDescriptor = require('./unicode-descriptor');
|
||||
tree.Negative = require('./negative');
|
||||
tree.Extend = require('./extend');
|
||||
tree.RulesetCall = require('./ruleset-call');
|
||||
tree.VariableCall = require('./variable-call');
|
||||
|
||||
module.exports = tree;
|
||||
|
||||
@@ -31,7 +31,7 @@ JsEvalNode.prototype.evaluateJavaScript = function (expression, context) {
|
||||
var variables = context.frames[0].variables();
|
||||
for (var k in variables) {
|
||||
if (variables.hasOwnProperty(k)) {
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
evalContext[k.slice(1)] = {
|
||||
value: variables[k].value,
|
||||
toJS: function () {
|
||||
|
||||
@@ -48,19 +48,8 @@ Media.prototype.eval = function (context) {
|
||||
this.rules[0].debugInfo = this.debugInfo;
|
||||
media.debugInfo = this.debugInfo;
|
||||
}
|
||||
var strictMathBypass = false;
|
||||
if (!context.strictMath) {
|
||||
strictMathBypass = true;
|
||||
context.strictMath = true;
|
||||
}
|
||||
try {
|
||||
media.features = this.features.eval(context);
|
||||
}
|
||||
finally {
|
||||
if (strictMathBypass) {
|
||||
context.strictMath = false;
|
||||
}
|
||||
}
|
||||
|
||||
media.features = this.features.eval(context);
|
||||
|
||||
context.mediaPath.push(media);
|
||||
context.mediaBlocks.push(media);
|
||||
|
||||
@@ -43,7 +43,7 @@ Definition.prototype.accept = function (visitor) {
|
||||
}
|
||||
};
|
||||
Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) {
|
||||
/*jshint boss:true */
|
||||
/* jshint boss:true */
|
||||
var frame = new Ruleset(null, null),
|
||||
varargs, arg,
|
||||
params = utils.copyArray(this.params),
|
||||
@@ -156,7 +156,7 @@ 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, /* the parameter variables*/
|
||||
[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
|
||||
|
||||
@@ -63,8 +63,8 @@ Node.prototype._operate = function (context, op, a, b) {
|
||||
};
|
||||
Node.prototype.fround = function(context, value) {
|
||||
var precision = context && context.numPrecision;
|
||||
//add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
|
||||
return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
|
||||
// add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded:
|
||||
return (precision) ? Number((value + 2e-16).toFixed(precision)) : value;
|
||||
};
|
||||
Node.compare = function (a, b) {
|
||||
/* returns:
|
||||
@@ -124,13 +124,13 @@ Node.prototype.removeVisibilityBlock = function () {
|
||||
}
|
||||
this.visibilityBlocks = this.visibilityBlocks - 1;
|
||||
};
|
||||
//Turns on node visibility - if called node will be shown in output regardless
|
||||
//of whether it comes from import by reference or not
|
||||
// Turns on node visibility - if called node will be shown in output regardless
|
||||
// of whether it comes from import by reference or not
|
||||
Node.prototype.ensureVisibility = function () {
|
||||
this.nodeVisible = true;
|
||||
};
|
||||
//Turns off node visibility - if called node will NOT be shown in output regardless
|
||||
//of whether it comes from import by reference or not
|
||||
// Turns off node visibility - if called node will NOT be shown in output regardless
|
||||
// of whether it comes from import by reference or not
|
||||
Node.prototype.ensureInvisibility = function () {
|
||||
this.nodeVisible = false;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ var Quoted = function (str, content, escaped, index, currentFileInfo) {
|
||||
this._index = index;
|
||||
this._fileInfo = currentFileInfo;
|
||||
};
|
||||
Quoted.prototype = new JsEvalNode();
|
||||
Quoted.prototype = new Node();
|
||||
Quoted.prototype.type = "Quoted";
|
||||
Quoted.prototype.genCSS = function (context, output) {
|
||||
if (!this.escaped) {
|
||||
@@ -22,13 +22,10 @@ Quoted.prototype.genCSS = function (context, output) {
|
||||
}
|
||||
};
|
||||
Quoted.prototype.containsVariables = function() {
|
||||
return this.value.match(/(`([^`]+)`)|@\{([\w-]+)\}/);
|
||||
return this.value.match(/@\{([\w-]+)\}/);
|
||||
};
|
||||
Quoted.prototype.eval = function (context) {
|
||||
var that = this, value = this.value;
|
||||
var javascriptReplacement = function (_, exp) {
|
||||
return String(that.evaluateJavaScript(exp, context));
|
||||
};
|
||||
var variableReplacement = function (_, name) {
|
||||
var v = new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context, true);
|
||||
return (v instanceof Quoted) ? v.value : v.toCSS();
|
||||
@@ -45,7 +42,6 @@ Quoted.prototype.eval = function (context) {
|
||||
} while (value !== evaluatedValue);
|
||||
return evaluatedValue;
|
||||
}
|
||||
value = iterativeReplace(value, /`([^`]+)`/g, javascriptReplacement);
|
||||
value = iterativeReplace(value, /@\{([\w-]+)\}/g, variableReplacement);
|
||||
value = iterativeReplace(value, /\$\{([\w-]+)\}/g, propertyReplacement);
|
||||
return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo());
|
||||
|
||||
@@ -122,7 +122,7 @@ Ruleset.prototype.eval = function (context) {
|
||||
// Evaluate mixin calls.
|
||||
for (i = 0; (rule = rsRules[i]); i++) {
|
||||
if (rule.type === "MixinCall") {
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
rules = rule.eval(context).filter(function(r) {
|
||||
if ((r instanceof Declaration) && r.variable) {
|
||||
// do not pollute the scope if the variable is
|
||||
@@ -135,8 +135,8 @@ Ruleset.prototype.eval = function (context) {
|
||||
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
||||
i += rules.length - 1;
|
||||
ruleset.resetCache();
|
||||
} else if (rule.type === "RulesetCall") {
|
||||
/*jshint loopfunc:true */
|
||||
} else if (rule.type === "VariableCall") {
|
||||
/* jshint loopfunc:true */
|
||||
rules = rule.eval(context).rules.filter(function(r) {
|
||||
if ((r instanceof Declaration) && r.variable) {
|
||||
// do not pollute the scope at all
|
||||
@@ -529,7 +529,7 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
// our new selector path
|
||||
newSelectorPath = [];
|
||||
|
||||
//construct the joined selector - if & is the first thing this will be empty,
|
||||
// construct the joined selector - if & is the first thing this will be empty,
|
||||
// if not newJoinedSelector will be the last set of elements in the selector
|
||||
if (beginningPath.length > 0) {
|
||||
newSelectorPath = utils.copyArray(beginningPath);
|
||||
@@ -559,7 +559,7 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
newSelectorPath.push(newJoinedSelector);
|
||||
}
|
||||
|
||||
//put together the parent selectors after the join (e.g. the rest of the parent)
|
||||
// put together the parent selectors after the join (e.g. the rest of the parent)
|
||||
if (addPath.length > 1) {
|
||||
var restOfPath = addPath.slice(1);
|
||||
restOfPath = restOfPath.map(function (selector) {
|
||||
@@ -654,7 +654,7 @@ Ruleset.prototype.joinSelector = function (paths, context, selector) {
|
||||
var nestedPaths = [], replaced, replacedNewSelectors = [];
|
||||
replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
|
||||
hadParentSelector = hadParentSelector || replaced;
|
||||
//the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
|
||||
// the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
|
||||
for (k = 0; k < nestedPaths.length; k++) {
|
||||
var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
|
||||
addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
|
||||
|
||||
@@ -5,12 +5,11 @@ var Node = require("./node"),
|
||||
var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) {
|
||||
this.extendList = extendList;
|
||||
this.condition = condition;
|
||||
this.evaldCondition = !condition;
|
||||
this._index = index;
|
||||
this._fileInfo = currentFileInfo;
|
||||
this.elements = this.getElements(elements);
|
||||
if (!condition) {
|
||||
this.evaldCondition = true;
|
||||
}
|
||||
this.mixinElements_ = undefined;
|
||||
this.copyVisibilityInfo(visibilityInfo);
|
||||
this.setParent(this.elements, this);
|
||||
};
|
||||
@@ -29,10 +28,9 @@ Selector.prototype.accept = function (visitor) {
|
||||
};
|
||||
Selector.prototype.createDerived = function(elements, extendList, evaldCondition) {
|
||||
elements = this.getElements(elements);
|
||||
var info = this.visibilityInfo();
|
||||
evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
|
||||
var newSelector = new Selector(elements, extendList || this.extendList, null, this.getIndex(), this.fileInfo(), info);
|
||||
newSelector.evaldCondition = evaldCondition;
|
||||
var newSelector = new Selector(elements, extendList || this.extendList,
|
||||
null, this.getIndex(), this.fileInfo(), this.visibilityInfo());
|
||||
newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
|
||||
newSelector.mediaEmpty = this.mediaEmpty;
|
||||
return newSelector;
|
||||
};
|
||||
@@ -66,14 +64,13 @@ Selector.prototype.match = function (other) {
|
||||
len = elements.length,
|
||||
olen, i;
|
||||
|
||||
other.cacheElements();
|
||||
|
||||
olen = other._elements.length;
|
||||
other = other.mixinElements();
|
||||
olen = other.length;
|
||||
if (olen === 0 || len < olen) {
|
||||
return 0;
|
||||
} else {
|
||||
for (i = 0; i < olen; i++) {
|
||||
if (elements[i].value !== other._elements[i]) {
|
||||
if (elements[i].value !== other[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -81,9 +78,9 @@ Selector.prototype.match = function (other) {
|
||||
|
||||
return olen; // return number of matched elements
|
||||
};
|
||||
Selector.prototype.cacheElements = function() {
|
||||
if (this._elements) {
|
||||
return;
|
||||
Selector.prototype.mixinElements = function() {
|
||||
if (this.mixinElements_) {
|
||||
return this.mixinElements_;
|
||||
}
|
||||
|
||||
var elements = this.elements.map( function(v) {
|
||||
@@ -98,7 +95,7 @@ Selector.prototype.cacheElements = function() {
|
||||
elements = [];
|
||||
}
|
||||
|
||||
this._elements = elements;
|
||||
return (this.mixinElements_ = elements);
|
||||
};
|
||||
Selector.prototype.isJustParentSelector = function() {
|
||||
return !this.mediaEmpty &&
|
||||
@@ -120,12 +117,9 @@ Selector.prototype.genCSS = function (context, output) {
|
||||
if ((!context || !context.firstSelector) && this.elements[0].combinator.value === "") {
|
||||
output.add(' ', this.fileInfo(), this.getIndex());
|
||||
}
|
||||
if (!this._css) {
|
||||
//TODO caching? speed comparison?
|
||||
for (i = 0; i < this.elements.length; i++) {
|
||||
element = this.elements[i];
|
||||
element.genCSS(context, output);
|
||||
}
|
||||
for (i = 0; i < this.elements.length; i++) {
|
||||
element = this.elements[i];
|
||||
element.genCSS(context, output);
|
||||
}
|
||||
};
|
||||
Selector.prototype.getIsOutput = function() {
|
||||
|
||||
@@ -65,7 +65,7 @@ Unit.prototype.usedUnits = function() {
|
||||
var group, result = {}, mapUnit, groupName;
|
||||
|
||||
mapUnit = function (atomicUnit) {
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
|
||||
result[groupName] = atomicUnit;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
var Node = require("./node"),
|
||||
Variable = require("./variable");
|
||||
|
||||
var RulesetCall = function (variable) {
|
||||
var VariableCall = function (variable) {
|
||||
this.variable = variable;
|
||||
this.allowRoot = true;
|
||||
};
|
||||
RulesetCall.prototype = new Node();
|
||||
RulesetCall.prototype.type = "RulesetCall";
|
||||
RulesetCall.prototype.eval = function (context) {
|
||||
VariableCall.prototype = new Node();
|
||||
VariableCall.prototype.type = "VariableCall";
|
||||
VariableCall.prototype.eval = function (context) {
|
||||
var detachedRuleset = new Variable(this.variable).eval(context);
|
||||
return detachedRuleset.callEval(context);
|
||||
};
|
||||
module.exports = RulesetCall;
|
||||
module.exports = VariableCall;
|
||||
@@ -3,7 +3,7 @@ var tree = require("../tree"),
|
||||
logger = require("../logger"),
|
||||
utils = require("../utils");
|
||||
|
||||
/*jshint loopfunc:true */
|
||||
/* jshint loopfunc:true */
|
||||
|
||||
var ExtendFinderVisitor = function() {
|
||||
this._visitor = new Visitor(this);
|
||||
@@ -137,7 +137,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
|
||||
iterationCount = iterationCount || 0;
|
||||
|
||||
//loop through comparing every extend with every target extend.
|
||||
// loop through comparing every extend with every target extend.
|
||||
// a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
|
||||
// e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
|
||||
// and the second is the target.
|
||||
@@ -368,7 +368,7 @@ ProcessExtendsVisitor.prototype = {
|
||||
},
|
||||
extendSelector:function (matches, selectorPath, replacementSelector, isVisible) {
|
||||
|
||||
//for a set of matches, replace each match with the replacement selector
|
||||
// for a set of matches, replace each match with the replacement selector
|
||||
|
||||
var currentSelectorPathIndex = 0,
|
||||
currentSelectorPathElementIndex = 0,
|
||||
|
||||
@@ -9,14 +9,14 @@ var CSSVisitorUtils = function(context) {
|
||||
CSSVisitorUtils.prototype = {
|
||||
containsSilentNonBlockedChild: function(bodyRules) {
|
||||
var rule;
|
||||
if (bodyRules == null) {
|
||||
if (!bodyRules) {
|
||||
return false;
|
||||
}
|
||||
for (var r = 0; r < bodyRules.length; r++) {
|
||||
rule = bodyRules[r];
|
||||
if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
|
||||
//the atrule contains something that was referenced (likely by extend)
|
||||
//therefore it needs to be shown in output too
|
||||
// the atrule contains something that was referenced (likely by extend)
|
||||
// therefore it needs to be shown in output too
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -24,28 +24,21 @@ CSSVisitorUtils.prototype = {
|
||||
},
|
||||
|
||||
keepOnlyVisibleChilds: function(owner) {
|
||||
if (owner == null || owner.rules == null) {
|
||||
return ;
|
||||
if (owner && owner.rules) {
|
||||
owner.rules = owner.rules.filter(function(thing) {
|
||||
return thing.isVisible();
|
||||
});
|
||||
}
|
||||
|
||||
owner.rules = owner.rules.filter(function(thing) {
|
||||
return thing.isVisible();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
isEmpty: function(owner) {
|
||||
if (owner == null || owner.rules == null) {
|
||||
return true;
|
||||
}
|
||||
return owner.rules.length === 0;
|
||||
return (owner && owner.rules)
|
||||
? (owner.rules.length === 0) : true;
|
||||
},
|
||||
|
||||
hasVisibleSelector: function(rulesetNode) {
|
||||
if (rulesetNode == null || rulesetNode.paths == null) {
|
||||
return false;
|
||||
}
|
||||
return rulesetNode.paths.length > 0;
|
||||
return (rulesetNode && rulesetNode.paths)
|
||||
? (rulesetNode.paths.length > 0) : false;
|
||||
},
|
||||
|
||||
resolveVisibility: function (node, originalRules) {
|
||||
@@ -146,9 +139,16 @@ ToCSSVisitor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
visitAnonymous: function(anonymousNode, visitArgs) {
|
||||
if (!anonymousNode.blocksVisibility()) {
|
||||
anonymousNode.accept(this._visitor);
|
||||
return anonymousNode;
|
||||
}
|
||||
},
|
||||
|
||||
visitAtRuleWithBody: function(atRuleNode, visitArgs) {
|
||||
//if there is only one nested ruleset and that one has no path, then it is
|
||||
//just fake ruleset
|
||||
// if there is only one nested ruleset and that one has no path, then it is
|
||||
// just fake ruleset
|
||||
function hasFakeRuleset(atRuleNode) {
|
||||
var bodyRules = atRuleNode.rules;
|
||||
return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
|
||||
@@ -161,9 +161,9 @@ ToCSSVisitor.prototype = {
|
||||
|
||||
return nodeRules;
|
||||
}
|
||||
//it is still true that it is only one ruleset in array
|
||||
//this is last such moment
|
||||
//process childs
|
||||
// it is still true that it is only one ruleset in array
|
||||
// this is last such moment
|
||||
// process childs
|
||||
var originalRules = getBodyRules(atRuleNode);
|
||||
atRuleNode.accept(this._visitor);
|
||||
visitArgs.visitDeeper = false;
|
||||
@@ -221,13 +221,13 @@ ToCSSVisitor.prototype = {
|
||||
},
|
||||
|
||||
visitRuleset: function (rulesetNode, visitArgs) {
|
||||
//at this point rulesets are nested into each other
|
||||
// at this point rulesets are nested into each other
|
||||
var rule, rulesets = [];
|
||||
|
||||
this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);
|
||||
|
||||
if (!rulesetNode.root) {
|
||||
//remove invisible paths
|
||||
// remove invisible paths
|
||||
this._compileRulesetPaths(rulesetNode);
|
||||
|
||||
// remove rulesets from this ruleset body and compile them separately
|
||||
@@ -253,7 +253,7 @@ ToCSSVisitor.prototype = {
|
||||
}
|
||||
visitArgs.visitDeeper = false;
|
||||
|
||||
} else { //if (! rulesetNode.root) {
|
||||
} else { // if (! rulesetNode.root) {
|
||||
rulesetNode.accept(this._visitor);
|
||||
visitArgs.visitDeeper = false;
|
||||
}
|
||||
@@ -263,7 +263,7 @@ ToCSSVisitor.prototype = {
|
||||
this._removeDuplicateRules(rulesetNode.rules);
|
||||
}
|
||||
|
||||
//now decide whether we keep the ruleset
|
||||
// now decide whether we keep the ruleset
|
||||
if (this.utils.isVisibleRuleset(rulesetNode)) {
|
||||
rulesetNode.ensureVisibility();
|
||||
rulesets.splice(0, 0, rulesetNode);
|
||||
@@ -321,72 +321,39 @@ ToCSSVisitor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_mergeRules: function (rules) {
|
||||
if (!rules) { return; }
|
||||
|
||||
var groups = {},
|
||||
parts,
|
||||
rule,
|
||||
key;
|
||||
_mergeRules: function(rules) {
|
||||
if (!rules) {
|
||||
return;
|
||||
}
|
||||
|
||||
var groups = {},
|
||||
groupsArr = [];
|
||||
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
rule = rules[i];
|
||||
|
||||
if ((rule instanceof tree.Declaration) && rule.merge) {
|
||||
key = [rule.name,
|
||||
rule.important ? "!" : ""].join(",");
|
||||
|
||||
if (!groups[key]) {
|
||||
groups[key] = [];
|
||||
} else {
|
||||
rules.splice(i--, 1);
|
||||
}
|
||||
|
||||
var rule = rules[i];
|
||||
if (rule.merge) {
|
||||
var key = rule.name;
|
||||
groups[key] ? rules.splice(i--, 1) :
|
||||
groupsArr.push(groups[key] = []);
|
||||
groups[key].push(rule);
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(groups).map(function (k) {
|
||||
|
||||
function toExpression(values) {
|
||||
return new (tree.Expression)(values.map(function (p) {
|
||||
return p.value;
|
||||
}));
|
||||
}
|
||||
|
||||
function toValue(values) {
|
||||
return new (tree.Value)(values.map(function (p) {
|
||||
return p;
|
||||
}));
|
||||
}
|
||||
|
||||
parts = groups[k];
|
||||
|
||||
if (parts.length > 1) {
|
||||
rule = parts[0];
|
||||
var spacedGroups = [];
|
||||
var lastSpacedGroup = [];
|
||||
parts.map(function (p) {
|
||||
if (p.merge === "+") {
|
||||
if (lastSpacedGroup.length > 0) {
|
||||
spacedGroups.push(toExpression(lastSpacedGroup));
|
||||
}
|
||||
lastSpacedGroup = [];
|
||||
groupsArr.forEach(function(group) {
|
||||
if (group.length > 0) {
|
||||
var result = group[0],
|
||||
space = [],
|
||||
comma = [new tree.Expression(space)];
|
||||
group.forEach(function(rule) {
|
||||
if ((rule.merge === '+') && (space.length > 0)) {
|
||||
comma.push(new tree.Expression(space = []));
|
||||
}
|
||||
lastSpacedGroup.push(p);
|
||||
space.push(rule.value);
|
||||
result.important = result.important || rule.important;
|
||||
});
|
||||
spacedGroups.push(toExpression(lastSpacedGroup));
|
||||
rule.value = toValue(spacedGroups);
|
||||
result.value = new tree.Value(comma);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
visitAnonymous: function(anonymousNode, visitArgs) {
|
||||
if (anonymousNode.blocksVisibility()) {
|
||||
return ;
|
||||
}
|
||||
anonymousNode.accept(this._visitor);
|
||||
return anonymousNode;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ function indexNodeTypes(parent, ticker) {
|
||||
// add .typeIndex to tree node types for lookup table
|
||||
var key, child;
|
||||
for (key in parent) {
|
||||
/*eslint guard-for-in: 0 */
|
||||
/* eslint guard-for-in: 0 */
|
||||
child = parent[key];
|
||||
switch (typeof child) {
|
||||
case "function":
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"performance-now": "^0.2.0",
|
||||
"phantomjs-prebuilt": "^2.1.7",
|
||||
"promise": "^7.1.1",
|
||||
"request": "^2.73.0",
|
||||
"phin": "^2.2.3",
|
||||
"time-grunt": "^1.3.0"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -148,7 +148,7 @@ testSheet = function (sheet) {
|
||||
});
|
||||
};
|
||||
|
||||
//TODO: do it cleaner - the same way as in css
|
||||
// TODO: do it cleaner - the same way as in css
|
||||
|
||||
function extractId(href) {
|
||||
return href.replace(/^[a-z-]+:\/+?[^\/]+/i, '') // Remove protocol & domain
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*jshint latedef: nofunc */
|
||||
/* 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/).
|
||||
|
||||
@@ -199,3 +199,16 @@
|
||||
html {
|
||||
color: #8080ff;
|
||||
}
|
||||
#boolean {
|
||||
a: true;
|
||||
b: false;
|
||||
c: false;
|
||||
}
|
||||
#if {
|
||||
a: 1;
|
||||
b: 2;
|
||||
c: 3;
|
||||
e: ;
|
||||
f: 6;
|
||||
/* results in void */
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@media (-o-min-device-pixel-ratio: 2/1) {
|
||||
@media (-o-min-device-pixel-ratio: 2) {
|
||||
.test-math-and-units {
|
||||
font: ignores 0/0 rules;
|
||||
test-division: 7em;
|
||||
|
||||
@@ -10,16 +10,17 @@
|
||||
background: url(data://img1.png);
|
||||
}
|
||||
.test4 {
|
||||
transform: rotate(90deg), skew(30deg);
|
||||
transform: scale(2, 4) !important;
|
||||
transform: rotate(90deg), skew(30deg), scale(2, 4) !important;
|
||||
}
|
||||
.test5 {
|
||||
transform: rotate(90deg), skew(30deg);
|
||||
transform: scale(2, 4) !important;
|
||||
transform: rotate(90deg), skew(30deg), scale(2, 4) !important;
|
||||
}
|
||||
.test6 {
|
||||
transform: scale(2, 4);
|
||||
}
|
||||
.test7 {
|
||||
transform: scale(2, 4), scale(2, 4), scale(2, 4) !important;
|
||||
}
|
||||
.test-interleaved {
|
||||
transform: t1, t2, t3;
|
||||
background: b1, b2, b3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*jshint latedef: nofunc */
|
||||
/* jshint latedef: nofunc */
|
||||
|
||||
module.exports = function() {
|
||||
var path = require('path'),
|
||||
@@ -45,21 +45,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);
|
||||
} else {
|
||||
//console.log("stopping queue");
|
||||
// console.log("stopping queue");
|
||||
queueRunning = false;
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,7 @@ module.exports = function() {
|
||||
if (err.stack) {
|
||||
process.stdout.write(err.stack + "\n");
|
||||
} else {
|
||||
//this sometimes happen - show the whole error object
|
||||
// this sometimes happen - show the whole error object
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
.wrap-mixin(@ruleset);
|
||||
|
||||
.desktop-and-old-ie(@rules) {
|
||||
@media screen and (min-width: 1200) { @rules(); }
|
||||
html.lt-ie9 & { @rules(); }
|
||||
@media screen and (min-width: 1200) { @rules() }
|
||||
html.lt-ie9 & { @rules() }
|
||||
}
|
||||
|
||||
header {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
@plugin "../plugin/plugin-tree-nodes";
|
||||
test-alpha();
|
||||
@@ -1,3 +0,0 @@
|
||||
SyntaxError: Alpha node returned by a function is not valid here in {path}functions-2-alpha.less on line 2, column 1:
|
||||
1 @plugin "../plugin/plugin-tree-nodes";
|
||||
2 test-alpha();
|
||||
@@ -231,3 +231,20 @@ html {
|
||||
color: mix(blue, @color2, 50%);
|
||||
}
|
||||
|
||||
#boolean {
|
||||
a: boolean(not(2 < 1));
|
||||
b: boolean(not(2 > 1) and (true));
|
||||
c: boolean(not(boolean((true))));
|
||||
}
|
||||
|
||||
#if {
|
||||
a: if(not(false), 1, 2);
|
||||
b: if(not(true), 1, 2);
|
||||
@1: if(not(false), {c: 3}, {d: 4}); @1();
|
||||
|
||||
e: if(not(true), 5);
|
||||
@f: boolean((3 = 4));
|
||||
f: if(not(@f), 6);
|
||||
|
||||
if((false), {g: 7}); /* results in void */
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@media (-o-min-device-pixel-ratio: 2/1) {
|
||||
@media (-o-min-device-pixel-ratio: 2) {
|
||||
.test-math-and-units {
|
||||
font: ignores 0/0 rules;
|
||||
test-division: 4 / 2 + 5em;
|
||||
|
||||
@@ -36,17 +36,20 @@
|
||||
.first-background();
|
||||
}
|
||||
.test4 {
|
||||
// Won't merge values from sources that merked as !important, for backwards compatibility with css
|
||||
.first-transform();
|
||||
.fifth-transform();
|
||||
}
|
||||
.test5 {
|
||||
// Won't merge values from mixins that merked as !important, for backwards compatibility with css
|
||||
.first-transform();
|
||||
.second-transform() !important;
|
||||
}
|
||||
.test6 {
|
||||
// Ignores !merge if no peers found
|
||||
.second-transform();
|
||||
}
|
||||
.test7 {
|
||||
// inherit !important from merged subrules
|
||||
.second-transform();
|
||||
.second-transform() !important;
|
||||
.second-transform();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,19 +7,19 @@ functions.addMultiple({
|
||||
return less.AtRule(arg1.value, arg2.value);
|
||||
},
|
||||
"test-extend": function() {
|
||||
//TODO
|
||||
// TODO
|
||||
},
|
||||
"test-import": function() {
|
||||
//TODO
|
||||
// TODO
|
||||
},
|
||||
"test-media": function() {
|
||||
//TODO
|
||||
// TODO
|
||||
},
|
||||
"test-mixin-call": function() {
|
||||
//TODO
|
||||
// TODO
|
||||
},
|
||||
"test-mixin-definition": function() {
|
||||
//TODO
|
||||
// TODO
|
||||
},
|
||||
"test-ruleset-call": function() {
|
||||
return less.Combinator(' ');
|
||||
@@ -32,9 +32,6 @@ functions.addMultiple({
|
||||
return true;
|
||||
},
|
||||
// These cause root errors
|
||||
"test-alpha": function() {
|
||||
return less.Alpha(30);
|
||||
},
|
||||
"test-assignment": function() {
|
||||
return less.Assignment("bird", "robin");
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user