Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape function with nested var failed #3314

Open
Corcules opened this issue Oct 2, 2018 · 10 comments · May be fixed by #3726
Open

Escape function with nested var failed #3314

Corcules opened this issue Oct 2, 2018 · 10 comments · May be fixed by #3726

Comments

@Corcules
Copy link

Corcules commented Oct 2, 2018

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

@rjgotten
Copy link
Contributor

rjgotten commented Oct 4, 2018

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 ));

@Corcules
Copy link
Author

Corcules commented Oct 8, 2018

Sorry, just try but not working with inline string conversion. exactly the same error.

@Corcules
Copy link
Author

Corcules commented Oct 8, 2018

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

@rjgotten
Copy link
Contributor

rjgotten commented Oct 8, 2018

The % function atleast should call toCSS for every node type which is not Quoted, i.e. a quoted string value:

'%': 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 */
result = result.replace(/%[sda]/i, function(token) {
var value = ((args[i].type === 'Quoted') &&
token.match(/s/i)) ? args[i].value : args[i].toCSS();
return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
});
}
result = result.replace(/%%/g, '%');
return new Quoted(string.quote || '', result, string.escaped);
}

However, it calls toCSS without arguments and it looks like the Color node type atleast expects some parameters there:

Color.prototype.toCSS = function (context, doNotCompress) {

@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.

@matthew-dean
Copy link
Member

@rjgotten 👍

@easingthemes
Copy link

For svg issue, I've overrided escape function.

  1. Create a plugin (my-plugin.js)
module.exports = {
    install: (less, pluginManager, functions) => {
        functions.add('escape', str => encodeURI(str.value));
    }
};
  1. 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.

@lumburr lumburr linked a pull request May 10, 2022 that will close this issue
3 tasks
@HelloWorld017
Copy link

HelloWorld017 commented Jul 5, 2023

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.

  1. --var: escape('<svg>'); is working fine, but yields --var: %3Csvg%3E;
  2. saving escape() result and evaluating the isstring 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}";
}

@rjgotten
Copy link
Contributor

rjgotten commented Jul 5, 2023

@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}";
}

@HelloWorld017
Copy link

HelloWorld017 commented Jul 5, 2023

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.

@Corcules
Copy link
Author

Corcules commented Jul 5, 2023

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 ) ;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants