-
Notifications
You must be signed in to change notification settings - Fork 191
Support for Less root functions, lookups, anonymous mixins #135
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
Conversation
Just to note: I tested this through just the regular (and updated) tests on this repo. I haven't tried this in a local development build of VSCode. |
One thing that's still kind of outstanding is that because rulesets can be maps in Less, the warning and squiggly lines about "unknown property"s is somewhat useless. Is there a way for those |
...Ping? |
Sorry, @aeschli was on vacation and so was I. I'll review it in December. |
@octref Ok no worries, just wanted to make sure it didn't get lost! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: in Less, there are more at-rules than @supports and @media that bubble, but I notice the core CSS parser only supports those two types as being nested. Not sure if that's worth addressing or not.
That's fine for now.
Overall looks good, just a few questions to understand the less features being added.
assertNode('$color', parser, parser._parseVariable.bind(parser)); | ||
assertNode('$$color', parser, parser._parseVariable.bind(parser)); | ||
assertNode('@$color', parser, parser._parseVariable.bind(parser)); | ||
assertNode('$@color', parser, parser._parseVariable.bind(parser)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are these? I don't know much about less, but from http://lesscss.org/features I understand these usages:
@color: #fff;
.foo {
color: @color;
background-color: $color;
}
Can you give me an example that uses @$
, $@
and $$
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a combination of two things.
- Less supports variables and (like PHP) variable variables. Meaning, the name (identifier) of a variable being referenced can itself be variable. So:
@@var
means "return the value of a variable with the id that@var
resolves to. If@var
isfoo
then@foo
is looked up/returned. - In a 2.x release, support for property referencing (
$prop
) was added. Basically it just means that properties are (more or less) variables.
Well it's not explicitly documented, you can technically then combine these features of variable variables, where the property identifier being looked up is variable, or the variable id being looked up is variable based on a property name.
Why someone would ever do this, I don't know, it's just a normal side-effect of combining these features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't compile with less 3.9:
@color: #fff;
@lookup: 'color';
.foo {
color: @@lookup;
background-color: $@lookup;
}
I guess we can add more less-specific language features in the future. Now as long as VS Code doesn't fail at parsing these less files, users can get by.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@octref You're right that that usage may not compile, but this does:
@dr: {
prop: value;
}
.box {
@lookup: prop;
foo: @dr[$@lookup];
}
For lookup values, I think I did the VSCode parsing to use any of the variable reference form. So, yeah, it may not compile, but VSCode should still not throw an unrecoverable parsing error.
It's also possible the code you wrote will work at some point, just for consistency.
|
||
assertNode('func(a, b; bar)', parser, parser._parseRuleSetDeclaration.bind(parser)); | ||
assertNode('func({a: b();}, bar)', parser, parser._parseRuleSetDeclaration.bind(parser)); | ||
assertNode('func(.(@val) {})', parser, parser._parseRuleSetDeclaration.bind(parser)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this allowed?
This in lessc 3.9 gives me errors:
func(@x) {
@x();
}
.foo {
func({a: b();});
}
less-test > lessc test.less
ParseError: Unrecognised input in /Users/octref/Code/work/less-test/test.less on line 12, column 10:
11
12 func(@x) {
13 @x();
I thought functions only start with dot, like .func() {}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're thinking of mixins. Mixins start with .
or #
, and those are defined in your stylesheet. Functions are defined in JavaScript. They accept a node (or nodes), and return a node. lighten()
and darken()
are examples of Less functions. After Less made it easier for users to define functions using @plugin
, the restriction on functions being only in a property's value was dropped. This way, authors can call a function that returns a ruleset, for example. Less also later added functions that are meant to be called around rules, such as each()
.
src/test/less/parser.test.ts
Outdated
}); | ||
|
||
test('Interpolation', function () { | ||
let parser = new LESSParser(); | ||
assertNode('.@{name} { }', parser, parser._parseRuleset.bind(parser)); | ||
assertNode('.${name} { }', parser, parser._parseRuleset.bind(parser)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is "Adds support for property references (
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to what's mentioned above, this is just a normal side-effect of treating properties as variables. That is, you can do interpolation in other values. Would this particular syntax in the above assertion ever make sense? Not really. But it's valid Less, which should be what the parser is checking for.
src/parser/lessParser.ts
Outdated
} | ||
|
||
public _acceptInterpolatedIdent(node: nodes.Node): boolean { | ||
public acceptRegexp(regEx: RegExp): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move this to cssparser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could probably do that.
src/parser/lessParser.ts
Outdated
return false; | ||
} | ||
|
||
public _parseRegexp(regEx: RegExp): nodes.Node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, seems useful enough that we can have it in cssparser.
src/parser/lessParser.ts
Outdated
|
||
while (accept() || | ||
node.addChild(this._parseInterpolation() || | ||
this.try(delimWithInterpolation))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can the conditions in the same line. It's hard to read what's inside the while
because of no indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Or maybe for really long conditions, move them all to an indented form?
As in:
while(
condition() ||
condition2()
) {
}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's better. this.try
and hasContent
on the same indent level was confusing to me.
src/parser/lessParser.ts
Outdated
@@ -361,9 +488,10 @@ export class LESSParser extends cssParser.Parser { | |||
} | |||
|
|||
public _parseInterpolation(): nodes.Node { | |||
// @{name} | |||
// @{name} Variable or | |||
// ${name} Property |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other ${prop}
confusion. Can you point me to the docs that describe this feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation is very brief and doesn't cover the interpolated form. It's here: http://lesscss.org/features/#variables-feature-properties-as-variables-new-
It should probably be added to Less docs, but it's valid. In a lot of cases for these, I pulled code directly from Less unit tests and added them to the language service tests. In fact, I opened Less unit tests in VSCode to see what was failing first, before adding language service tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move parse/accept regex to base parser and this should be good to go. Thanks!
@matthew-dean Thanks a lot for your help! We're happy to have your expertise! Most of the changes are good. To (hopefully) make it simpler to work on this, I already pushed some of the uncontroversial changes, see 5e7a590 What I don't like so much are changes related to the map lookups. The lookup is modelled as a child to variables and mixins. I think it is cleaner if we do it in the term, like an an operator (e.g. the % operator). |
I'm unclear what you're saying...? |
@matthew-dean My suggestion would be to add the support to
That allows indexed access of every term which is probably more than necessary, but would keep the variables and mixins as is. |
Although some of the changes are already in, we'll put the changes on release notes for next month when we merge the whole PR. |
Sorry, will try to get back to this soon and the requested changes when I can find some time. |
@radium-v Would you have time to fix conflicts and address the few changes requested? I've just got a full schedule at work + parenting. |
@matthew-dean sure, I'll dive in this week. |
Sooo, is anyone still on this? As it has missed its milestones and I would love to see this implemented but do not have the skills to finish this. |
@kevinramharak I apologize. As someone who coordinates open source work, I know it's frustrating when a PR seems so close but languishes in changes. I just haven't had the extra cycles for any development on the side. Hopefully @radium-v can get to it? On a long enough timeline, I should be able to return to a pile of Less maintenance stuff, which includes this, but I don't yet have a slot in my schedule. |
@kevinramharak @matthew-dean I also apologize, I overpromised when I volunteered to pick this up. I do still intend to pick it up and run it to the finish line, This is a blocker for radium-v/Better-Less#14 and I'm finally able to get back to it. |
I've merged master and moved methods according to feedback. However, I found that with even the base-level merge I was getting unrelated errors on SCSS (which was logging console errors but not reporting as errors to the test runner?) and an error with a property in the CSS actions test. Can you take a look? |
It's too late in our development week for July, but I'll try to review and make sure this goes in for August. Thanks again for your work! |
@octref No problem! |
@matthew-dean Thanks a lot for your work! Can I ask you what's the less version this supports up-to? If I remember correctly it's 3.9.0 and there's no syntax change in 3.10.0 as far as I can tell. I'll start to link issues fixed by your PR. Thanks again 👍 🎉 |
There's probably a few bugs that was fixed in 5e7a590 #135 (comment) that I failed to link to. Thanks again for bringing the less support up-to-date 👍 |
@octref Less 3.10 was a minor version bump just because I converted the Less.js project to ES2015 modules, and as a result, was more than just a bugfix? (Not really sure how that fits into Semver lol.) But to answer your question, no, there have been no syntax changes and there are none currently planned. The last major ones were the "rulesets-as-maps" feature, and the ability to call functions on any node, which this should cover. |
This fixes a number of errors in the language service parser for CSS/Less (that are not covered in microsoft/vscode#43087).
@ruleset[@lookup]
or#ns.mixin(@arg)[prop]
$prop
and interpolated${prop}
)100: 100
or even10px: true
if someone wanted to get crazy*. The CSS parser parses them as any number of token types (number
ordimension
), so there's a regex parsing function added in the Less parser to be more forgiving of property names.each()
functionif()
,boolean
,range()
, andeach()
functions to Less completions@supports
and@media
that bubble, but I notice the core CSS parser only supports those two types as being nested. Not sure if that's worth addressing or not.)nestedProperties
}
like any other block)@supports (
as being parsed as a VariableCall. Checks for whitespace.* The declaration of
100
as a property name is not crazy; it's actually a real-world use case of a conversion of Bootstrap 4 maps to Less maps. See: https://github.com/seanCodes/bootstrap-less-port/blob/35390325fad4e23e037396dd19081a57d4189579/less/_variables.less#L24