less.js
less.js copied to clipboard
Escape function with nested var failed
Version
Less 3.8.1 via CodeKit
description
An error is thrown when escaping color variable and using it in an other var as string. No error with Less 2.x
A less var, svg image for data-uri, with a nested less var "@color-icone" for fill color
@icone-arrow-next : "data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 37'><path fill='@{color-icone}' d='M31.1 0l-1.5 1.5 15.5 16H0v2h45.1l-15.5 16 1.5 1.5L49 18.5z'/></svg>";
Using the var elsewhere
#selector { @color-icone : escape(#ffffff); background-image : url( @icone-arrow-next ) ; }
The error come with the escape function which transform the color code '#ffffff' to '%23ffffff'. No error without the escape function but the color string is not encoded...
error message
SyntaxError: Invalid % without number in /Users/path/to/file
Have you tried first converting to a string? The escape
function is documented as only accepting strings as its parameter, after all.
You can perform the conversion inline with the escape operation by using the %
format function:
@color-icone : escape( %( "%s", #ffffff ));
Sorry, just try but not working with inline string conversion. exactly the same error.
Fews more tests :
@color-icone : escape( #ffffff ); @color-icone : escape( %( "%s", #ffffff ));
Both are working with Less 2.7.1.
Both not working with Less 3.8.1
The %
function atleast should call toCSS
for every node type which is not Quoted
, i.e. a quoted string value:
https://github.com/less/less.js/blob/a84358d2956d3245f45083adc50069119de2e431/lib/less/functions/string.js#L22-L36
However, it calls toCSS
without arguments and it looks like the Color
node type atleast expects some parameters there:
https://github.com/less/less.js/blob/a84358d2956d3245f45083adc50069119de2e431/lib/less/tree/color.js#L70
@matthew-dean I think we have ourselves a bug here, right?
[EDIT]
Yup definitely a bug. It looks like the general implementation in tree/node.js
expects toCSS
to always be called with a context parameter as well.
@rjgotten 👍
For svg issue, I've overrided escape
function.
- Create a plugin (
my-plugin.js
)
module.exports = {
install: (less, pluginManager, functions) => {
functions.add('escape', str => encodeURI(str.value));
}
};
- Import a plugin:
@plugin './my-plugin';
Original escape
function v3.9.0
encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B').replace(/\(/g, '%28').replace(/\)/g, '%29'));
For some reason, full replacement was failing, even in the plugin.
SyntaxError: Invalid % without number in /Users/path/to/file
Unfortunately, this error also occurs when it's not dealing with the color. (Example) And also occurs when it's not dealing with the svg string. (Example)
I have tried the @easingtheme 's solution, and it seems working fine.
Update:
It seems that escape()
is not returning the string.
--var: escape('<svg>');
is working fine, but yields--var: %3Csvg%3E;
- saving
escape()
result and evaluating theisstring
returns false
So if we format the escape result to string, it seems working fine.
.a {
@svg: %('%s', escape('<svg></svg>'));
--var: "data:image/svg+xml,@{svg}";
}
@HelloWorld017 : So if we format the escape result to string, it seems working fine.
.a { @svg: %('%s', escape('<svg></svg>')); --var: "data:image/svg+xml,@{svg}"; }
The escape
function is documented as returning the string in literal form - i.e. without quotes. That is a hard guarantee of its output. Therefore, the following should be functionally equivalent to your example - just without all the additional run-around:
.a {
@svg : escape("<svg></svg>");
--var : "data:image/svg+xml,@{svg}";
}
Therefore, the following should be functionally equivalent to your example - just without all the additional run-around:
But even though it is quoted using the "@{svg}"
interpolation, it does not work with the error "SyntaxError: Invalid % without number", just like my first example.
Finally i use that trick : Escaping the color string directly give the syntax error, but assign the color string to a variable then escaping the variable works. This may help to understand why...
Not working escape > throw syntax error :
@icone-arrow-next : "data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 37'><path fill='@{color-icone}' d='M31.1 0l-1.5 1.5 15.5 16H0v2h45.1l-15.5 16 1.5 1.5L49 18.5z'/></svg>";
selector {
@color-icone : escape( #ffffff ) ;
background-image:url( @icone-arrow-next ) ;
}
Working :
@icone-arrow-next : "data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 37'><path fill='@{color-icone}' d='M31.1 0l-1.5 1.5 15.5 16H0v2h45.1l-15.5 16 1.5 1.5L49 18.5z'/></svg>";
selector {
@c : #ffffff ;
@color-icone : escape( @c ) ;
background-image:url( @icone-arrow-next ) ;
}