I am using less.js (1.3.0) to parse less to css on the client side. Inside the parsers' callback I want to get the value for each variable. i tried the following without success.
var data = "@colour: red; #example { background-color: @colour; }",
parser = new less.Parser({});
parser.parse(data, function (error, root) {
console.log( root.toCSS() );
var varsDef = root.variables();
for (k in varsDef) {
console.log(varsDef[k]);
// how to get the value for the var?
//not working
console.log(varsDef[k].eval());
//not working
console.log(varsDef[k].toCSS());
//is an object but looking for a string value
console.log(varsDef[k].value);
//returns an empty string
console.log(varsDef[k].value.toCSS());
}
});
Neither eval() nor the toCSS() gave me any results. I do not understand the less parsers' inner workings. Each variable object has a variable property varsDef[k].value which is an object itself. But I just need the string value of the variable.
Does anyone know how to get the variables' values as a string?
varsDef[k].value.toCSS()
should be the value
varsDef[k].name
should be the variable name
varsDef[k].toCSS()
returns nothing because it is a variable - in CSS variables do not output.
i ran into this problem recently and it bit me because, like you, i had the same instinct of running something like very much like the code you wrote above but for complex variables along the lines of
@redColor: #900; // responds to .toCSS()
@fooColor: desaturate(@redColor, 20%); // both of these error out
@barColor: lighten(@fooColor, 10%); // when calling .toCSS()
you'd get this nested tree.Value
for @barColor
which was this nested representation of the parse tree, so it would say, unhelpfully that barcolor: {[value: {value: [{lighten: {...}}]}]}
or somesuch. my parsing-fu is pretty bad because i would always end up with some object at some point which would no longer respond to me invoking tree.toCSS on it, so i gave up on that route.
Instead, what i did was generated a nonsense .less file with an import rule and a nonsense rule, like so
@import "varfile.less";
.foo {
redColor: @redColor;
fooColor: @fooColor;
barColor: @barColor;
}
less will happily parse such a file, it doesn't care if redColor
is a real css property or not, it just ignores it and does all the substitutions where it has to dutifully. And so you actually end up with a single rule css file that you can easily parse since it's very straightforwardly marked up. it looks like this:
.foo{
redColor: #990000;
fooColor: #8a0f0f;
barColor: #b81414;
}
this is, coincidentally, the easiest file to parse. it practically begs to be turned into json or what have you. granted, the path to here is pretty comical. i suspect it's because a variable without a rule is still fair game to be modified within the rule itself, but i could just be rationalizing that.
assuming you only want to extract the final values of your less vars and not the semantic values of your less vars, it's pretty handy. if you want semantics, it seems better to just parse the actual less file.
i ended up writing this in node and after i got past my own objections to how dodgy it felt, it worked quite well and fed me a json dict with my project's variables. you can take a look, it's on github at nsfmc/less-extractor which basically takes a basic config file and then writes to stdout a json dict. it's inelegant, but it totally works, even if it's a bit hackish.
your original question asked about doing this entirely client-side, so that would appear to rule out that github project, but the idea is very similar: you want to be able to access the original less file as part of some xhr request, parse it to get the variable names, build a less string, parse that, and then the rest of the code is just string building and run of the mill parsing.
hope that helps you!
I was also having issues with the less parser too; doing it that way was getting ridiculous with recursive checking of tree nodes.
If you wan't the actual values as opposed to the CSS generated (as per the above answer), the best way is to probably manually parse the file's text.
This function returns a key/value pair for each of the variables in a given less file. It wont work if the LESS file has multiple values per line, you could make it better with regex. I used it to parse bootstrap's variables file, which works nicely.
getLessVars = (lessStr) ->
lines = lessStr.split('\n')
lessVars = {}
for line in lines
if line.indexOf('@') is 0
keyVar = line.split(';')[0].split(':')
lessVars[keyVar[0]] = keyVar[1].trim()
return lessVars