less.js icon indicating copy to clipboard operation
less.js copied to clipboard

Global Variables with a literal "." in the value causes the variable to be undefined

Open rdwoodring opened this issue 2 years ago • 14 comments

To reproduce: This can be reproduced using the CLI or the programmatic API. Assuming that LESS is already installed, it is most straightforward to reproduce using the CLI:

echo "body { color: @buildVersion; }" | npx lessc --global-var="buildVersion=a.hello" -

On the other hand, removing the literal period allows this to work:

echo "body { color: @buildVersion; }" | npx lessc --global-var="buildVersion=hello" -

LESS Code:

body { color: @buildVersion; }

Current behavior: The LESS compiler throws an error that the global variable is undefined.

Expected behavior: The LESS compiler should not throw an error and the global variable should be defined.

Environment information:

  • less version: 3.5.0 - 4.1.3 (current)
  • nodejs version: 16.13.2
  • operating system: Windows

Appears to have been introduced in 3.5.0. Version 3.0.4 appears to be working fine.

rdwoodring avatar Dec 13 '22 20:12 rdwoodring

What's the use case?

matthew-dean avatar Apr 01 '23 17:04 matthew-dean

My use case is that we're cache busting things like background images, font files (font icons), etc. Based on the semantic version of my web app. That global variable gets appended to the url or the resources in a query string and so cache busts when we roll out a new version .

Certainly we could select some other string on which to cache bust, but as noted, we have existing code in the wild that's already working using the semantic version number on an older version of less.

Hopefully that makes sense.

EDIT: I should add that I'm happy to submit a PR to resolve, just might need a little help where to look. I spent a little bit of time triaging but just didn't have bandwidth during my daily work to really dig in. Also wanted to understand if this was a known issue etc. Before committing the time

rdwoodring avatar Apr 01 '23 19:04 rdwoodring

I am working on this.

Stegen54 avatar Jul 07 '23 17:07 Stegen54

After conducting deep research into the issue, I discovered that some special characters were excluded (on purpose) when variables are to be declared. Here is a list of them:

., #, @, $, +, /, ', ", *, `, (, ;, {,} and -

These were excluded because they are used as selector elements when executing some of the features of Less.

In this case, permitting a literal period to be used when declaring a variable causes some important functionality of Less to fail:

@rdwoodring, if you insist on using a literal period when declaring a variable, you can include them in quotes like this:

echo "body { color: @buildVersion; }" | npx lessc --global-var="buildVersion='a.hello'" -

Conclusion: I think this is by design and not a bug.

@matthew-dean, can you confirm?

praisennamonu1 avatar Aug 01 '23 18:08 praisennamonu1

@praisennamonu1 Yes, that sounds right. While the parsing is not 100% identical to the CSS spec, in general (to my recollection), variable names correspond with the rules for a CSS identifier. That is, in general, it's alphanumeric + dash as the only valid characters. (CSS does allow for escapes, such that .a\.class I believe is a valid class name with an actual dot in it, but Less is more strict about variable names.

matthew-dean avatar Aug 02 '23 14:08 matthew-dean

Still seems like a regression to me given that it's a breaking change somewhere between 3.0.4 and 3.5.0, but I won't argue.

This is probably enough info for me to find a workaround to move forward and obviously up to you, @matthew-dean , if you want to close this issue or keep it open

rdwoodring avatar Aug 02 '23 15:08 rdwoodring

@rdwoodring Workaround: use string ecsaping if you really need this

@buildVersion: e("a.hello");
body { color: @buildVersion; }

results in

body {
  color: a.hello;
}

lubber-de avatar Aug 15 '23 16:08 lubber-de

A good use case for needing to be able to put some of those excluded characters. Setting a global variable for a cdn domain or path. Development builds use http://cdn01.example.com/path/base.css and production builds use http://cdn02.example.com/path/base.min.css

johnwc avatar Nov 15 '23 20:11 johnwc

Oh wait a minute, I think I mis-read the original post. This is not about periods in the variable, but periods in the value, correct?

matthew-dean avatar Nov 21 '23 17:11 matthew-dean

Yep, in the value. My use case is that we have a custom library of font icons imported in a less file. We cache bust the url for that font file using the current version of our software as a query parameter on the url. So semantic version numbers like 6.4.2 no longer work as the variable value.

rdwoodring avatar Nov 21 '23 19:11 rdwoodring