-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Fixes #2270 - Adds each() function to Less functions #3263
Conversation
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.
Failed Travis CI build for Node 8?
return items; | ||
}; | ||
|
||
functionRegistry.addMultiple({ |
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.
Love the movement of the functions into the file where they're most relevant!
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.
👍
lib/less/functions/list.js
Outdated
key = new Dimension(i); | ||
value = item; | ||
} | ||
newRules.push(new Declaration('@value', |
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.
Since these are special reserved variables now, I wonder if we make them less likely to conflict with variable names developers might be using? Like @__value
or @VALUE
? Is there precedent for reserved variable names?
On a related note, I know "key" and "index" have subtle flavor differences, but I wonder if we minimize reserved variables by just using either one or the other. Is there a case where we'd need both that I'm overlooking?
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.
Well:
a) These vars are only bound specifically within the context of this function, so how would this possibly conflict?
b) Less already binds an @arguments in the context of mixins, so it would be strange to start suddenly namespacing injected vars in that way.
On a related note, I know "key" and "index" have subtle flavor differences, but I wonder if we minimize reserved variables by just using either one or the other. Is there a case where we'd need both that I'm overlooking?
You can iterate an each()
over a ruleset, which will then have, for each entry (declaration), a @key
(property or var name), @value
(value), and @index
(numerical position). Unless it should be @name
instead of @key
?
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.
Less already binds an
@arguments
in the context of mixins...
Precedent wins for me.
I think @name
is probably more likely to have some global value assigned to it by authors, so I think @key
is probably better. This would be the only kind of conflict I could see happening with any of these reserved variables.
Would there be any value in warning an author when s/he assigns a value to a variable that shares its name with a "reserved" var? Nothing that would block compiling, but just to make the dev aware?
TL;DR: I'm convinced. No changes needed here. My only other thought would be @i
instead of @index
, maybe.
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.
Along similar lines, I think better to be explicit (@index
vs @i
, and also precedent of full names)
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.
Besides; if an author desperately wants a short-hand because their loop-body contains long lines of code they want to condense: nothing is preventing them from doing a quick @i : @index
, right?
And for formal parameters, it's better to have formal names.
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.
And for formal parameters, it's better to have formal names.
Yep.
test/less/functions-each.less
Outdated
@i: (@index - 1); | ||
|
||
each(@value; { | ||
@a: extract(@alpha, (@i * 2 + @key)); |
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'm having trouble following this test. Is it to test calculations with index and key? Maybe we split it into 2 tests, one to test loops in loops, and another to test calculations? Or we could just add comments to clarify what's being tested.
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 actually threw me when I went back and saw it, even though I wrote it (a couple years ago). Basically it's just demoing that you can get a reference the scoped index of parent in a nested loop. So in an loop of a loop, you can get parent values / indexes along with local by assigning them to a different var in the parent.
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.
Hmmm... 🤔 this won't actually work the way I had it before, because of lazy evaluation. If you do @i: @index
for example, it's evaluated when called.
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.
So I'm wondering what to do about this. Technically you can nest each()
, but if you can't specify your var names, and vars are lazy evaluated, then you can't reference the "parent" index/key/value. Does that matter?
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.
Hmm...yeah, loops would need to expose them as different variables...maybe we expose each as a list/map?
each(@list1, {
@value-loop1: @each[@1][value]; // or @each[@1][]
@key-loop1: @each[@1][key];
@index-loop1: @each[@1][index]; // or @i-loop1: @each[@1][i];
each(@list2, {
@value-loop2: @each[@2][value]; // or @each[@2][]
@key-loop2: @each[@2][key];
@index-loop2: @each[@2][index]; // or @i-loop2: @each[@2][i];
})
})
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 you need to go the generic route and add a function that can be used to selectively force in-place/eager evaluation? Would maybe help with the &()
feature as well, since that also needs to be eager.
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 you need to go the generic route and add a function that can be used to selectively force in-place/eager evaluation? Would maybe help with the &() feature as well, since that also needs to be eager.
Can you clarify? Note that I wrote this comment before defining / implementing the anonymous mixin syntax. I really don't think we want to change the behavior of scoped vars.
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 something that I was musing about.
There is - in a way - a method already to force eager evaluation of a variable; it has to be done before offering the variable's value to the function in a function call node. The 'problem' there is that the evaluation of the actual function to which the variable is passed, is still lazy.
i.e. in @a: foo(@b)
@b
might be eagerly evaluated when foo
executes, but the execution of foo
itself is still lazy and depends on tapping / accessing @a
.
But if there were a way to force the evaluation of a function like foo
to be internally eager and just cache its evaluated value until its pulled for by a lazy execution of a larger expression or chain of variable assignments in which foo(@b)
partakes, then in effect @b
would have been evaluated eagerly.
It means you would be able to force-eval loop variables at the correct time and possibly support other interesting / complex scenarios that have problems with lazy evaluation right now.
Ofcourse; with custom parameter names now introduced to each()
, these problems should be resolved already. There is no longer a lazy chain of @index
(or @key
or @value
) variable-aliasing assignments to walk through. So the point - atleast for this PR - no longer applies.
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.
Okay, yeah for this one, it's no longer an issue once you can name vars.
Do you approve of this PR as written then?
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.
@calvinjuarez Also it would be good to get your sign-off if good too, since it's a new syntax construct for Less. If there's hesitation about it, let me know.
See new tests and parser updates. // nested each
each(10px 15px, 20px 25px; {
// demonstrates nesting of each()
each(@value; #(@v, @k, @i) {
nest-@{i}-@{index}: @v @k;
});
}); produces: nest-1-1: 10px 1;
nest-2-1: 15px 2;
nest-1-2: 20px 1;
nest-2-2: 25px 2; |
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.
Do nested .() {}
loops work? If so, we should add a test testing that .()
defines unique mixins each time you nest.
nest-@{i}-@{index}: @v @k; | ||
}); | ||
}); | ||
|
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
nest-1-2: 20px 1; | ||
nest-2-2: 25px 2; | ||
padding: 10px 20px 30px 40px; | ||
} |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This is ready. My final question is just whether the reserved variables To be clear, though, this isn't a blocking comment/discussion by any means. This is good to go. |
@calvinjuarez I think the injected vars are nice to have? It just limits the amount of boilerplate you have to write. |
Fixes #2270