Open matthew-dean opened 8 years ago
Added (failing) tests for namespacing. No work has been done / started on the parsing / evaluation side. https://github.com/less/less.js/commit/3642ca9ddf287f94cc48268b1d37064d0c765774
Yes, there's no major conflict ... yet. Well, not counting CSS requires no space there, so if this goes beyond grid
properties having no colors, in compressed CSS it could possibly appear#abc[foo]
some day (by now it could only be very exotic .42[bar]
).
My main concern though is a very different semantics of similar looking values in the same context
(If I'm not mistaken, there was no such precedent yet beside /
). Sure something like:
grid-template-rows: [main-start] .main[content] [content-start];
looks pretty exotic so far but who knows where they will end with these []
eventually.
--
P.S. There's also #ns[var][var][var]
potential in out syntax (if nested variables are DRs) and it goes even more close to some compressed grid
values.
🤔
No, I see where you're coming from, just from the readability standpoint. The no spaces required is not as big a deal but..... I understand it's avoidable. Hmm.........
Okay, well we've got some choices here....
()
are out. Math.ns->member
seems like a non-starter, since the name space can be .class-
, can it not? So we'd be confusing the -
as the end of the NS with ->
as referencing the prop/var. Unless.......Some possibilities:
.ns>>prop
.ns>>@var
-- So like an extension of the #ns>.mixin
idea, piercing further into the rules? However .ns>>@dr>>prop
gets kinda messy-looking.ns[{prop}]
? [shrug]@{.ns[prop]}
- extend interpolation syntax to wrap any identifier lookup? (Which is basically where we started, but I'm proposing a bit of a syntax merge here.)${.ns[prop]}
- same as above but muddies the waters less. You end up with $prop
${prop}
${@var}
${.ns[prop]}
${.ns[@var]}
${.ns[@dr][prop]}
#1
is maybe cleanest, but still potentially ambiguous. As I wrote out #4
it seems to solve a lot of on the ambiguity side, and seems to logically connect with property lookup in a decent way. You end up with a clearer sentence with:
grid-template-rows: [main-start] ${.main[content]} [content-start];
Also, #4
has the problem of string/selector interpolation already baked-in and solved. Kinda win-win. This basically merges the ambiguous syntaxes ${ns prop}
and @{ns var}
with the more explicit ns[@var]
, so that you end up context-safe, and also clarity of syntax: ${ns[@var]}
Thoughts?
Note, #4
also solves this problem I wrote out that kicked off the thread:
val: @{@dr var}; // which one does @ belong with?
Instead of trying to do some kind of magical transposition of applying the leading @
onto the internal identifier, you end up with:
val: ${@dr[@var]}; // It's clear the identifier is @var within @dr and `${}` is a referencing lookup
And then you can grab multiple levels deep:
val: ${@dr1[@dr2][@var]};
And then if we do the mixin aliasing feature here, we could end up with something like.....
#usage {
@theme: ${.my-theme-ns(red)};
@theme.some-mixin();
border: 1px solid ${@theme[@secondary]};
}
// Unless only this would be required; we can work that out separately
//#usage {
// @theme: .my-theme-ns(red);
// @theme.some-mixin();
// border: 1px solid ${@theme[@secondary]}; -- ${} only needed for single values, not rules?
//}
The last one is spitballing, I just wanted to make sure we weren't screwing up that thread.
${ns[@var]}
Honestly? I always hated this @{}
syntax the most in Less. I'd rather prefer #ns->ident
or #ns<ident>
then. Sure, this is more like irrational hate (having just a bit of rationality for "too verbose", "too {}
-bock-like looking), counting @{}
is already there and nothing can be done with it. But, yet again to be really honest and whining, I'd really agree for any alternative instead (incl. conflicting #ns[ident]
or ugly @ns|ident
) :).
Regarding option 1 of .ns>>prop
:
The CSS Selectors Level 4 spec introduces >>
as an explicit descendant combinator, so you probably want to leave it alone.
I'd like to suggest a 5th option: .ns[[prop]]
Afaik that will suitably disambiguate it from grid templates.
The @ns|ident
suggestion is actually nice as well, imho; reminiscent of XML namespaces in CSS selectors.
The
@ns|ident
suggestion is actually nice as well
:) Curiously I also realized it might be not so bad when I see it with that particular font above, but in other fonts it's much more weird, e.g.: .ns|intend (looks like .nsjintend/.nslintend).
@seven-phases-max
Honestly? I always hated this @{} syntax the most in Less. I'd rather prefer #ns->identor #ns
then. Sure, this is more like irrational hate (having just a bit of rationality for "too verbose", "too {}-bock-like looking), counting @{} is already there and nothing can be done with it. But, yet again to be really honest and whining, I'd really agree for any alternative instead (incl. conflicting #ns[ident] or ugly @ns|ident) :).
Haha fair enough, and I came back today to be like, "uuuuugh do we REALLY have to wrap all namespaced properties"?
For the same reason, .ns[[prop]]
seems like an annoying level of wrapping.
I never considered #ns<ident>
. That's cool and nothing immediately strikes me as bad about it.
Usage:
.test {
val: @dr<@var>;
val: @dr<@dr><@var>;
grid-template-rows: [main-start] .main<content> [content-start];
}
vs.
.test {
val: @dr|@var;
val: @dr|@dr|@var;
grid-template-rows: [main-start] .main|content [content-start];
}
🤔 The pipe |
I wonder if it's almost too gentle of a separator, similar to your instincts. But on the other hand, multiple ><
starts to look a little busy (although that's gonna be the more rare use case.
🤔 🤔 🤔 I dunno, the pipe is kinda fucking cool. Very clean result. vs.....
.test {
val: @dr->@var;
val: @dr->@dr->@var;
grid-template-rows: [main-start] .main->content [content-start];
}
HMMMMMMMM... the explicit nature of ->
very strongly conveys the semantic meaning of a retrieval here, and adds more clarity in the grid-template-rows
value. And maybe the limitation of "don't end identifiers with a hyphen" (which, who would do that anyway?) is no big deal.
And ->
is more tied in languages to map access than |
probably. Like, if we're not doing brackets []
then it's probably the #2
most used, no?
So yeah, I would agree with all 3 of these options over ${ns[ident]}
. These are good suggestions.
Ha, I noticed after posting that Github did some good code coloring with <>
and ->
whereas pipes look kinda dead. This is minor, but enough to probably bump |
more solidly to last place on that list of 3 for me.
The nice thing about ->
is that you can use legacy mixin syntax to do:
.test {
val: #ns > .mixin -> @var;
}
vs.
.test {
val: #ns > .mixin <@var>;
}
That is, when space-separated, the latter starts to look more strange and inconsistent.
These ->
and <...>
were just random examples of course (I simply borrowed from C++) - I did not really considered them seriously. Sure, if we go deeper they reveal to be not very suitable, too ambiguous even if there's no direct conflicts:
.ns->ident
- is it a member access or .ns-
greater than ident
?.ns<ident> another
- is it boolean (.ns < ident) > another
?
etc.So please do not treat these as some kind of proposal (they were really just random inspirational goodies to stress individual habits. :)
That is, when space-separated, the latter starts to look more strange and inconsistent.
That's another story. There're reasons (and this is one of them) why in either C-like language you (ideally) always write member-access and subscript operators w/o spaces. E.g. in JavaScript:
let a =objects[12 ]. memberArray [ 42]
;
is valid (if I'm not mistaken) but we never write it like this :) (it's always obj.member
and array[index]
thus the legacy #ns > .mixin
-like stuff (when it's a namespace.member
thing and not a CSS selector at all) is really a bogus formatting style).
These -> and <...> were just random examples of course (I simply borrowed from C++) - I did not really considered them seriously. Sure, if we go deeper they reveal to be not very suitable, too ambiguous even if there's no direct conflicts:
So please do not treat these as some kind of proposal (they were really just random inspirational goodies to stress individual habits. :)
[sigh]
Okay. Well... suggestions?
I still do like #ns[ident]
thing the most so far. I was just wondering if we could invent something comparable considering the new []
baby of CSS. It seems we can't :)
Technically I think if you've already started experimenting with implementation it's fine to go with []
and if necessary it can be changed to something else (#ns≥iden≤
) even after RC.. I assuming the most tedious part there will be the evaluation code while the parsing part (at east what for what comes after #ns/.ns
) is relatively easy (thus not so critical to later changes).
I still do like #ns[ident] thing the most so far. I was just wondering if we could invent something comparable considering the new [] baby of CSS. It seems we can't :)
lol @seven-phases-max sometimes it's hard to glean what your actual position is. 😉
Okay..... if #ns[ident]
works in the short term, let's do it. No, I haven't started any implementation and I'd really prefer to not do that work myself (unless I can finally convince my team at work to switch from Sass to Less, which.... no luck so far). Basically all I did was start a new branch, and check-in the tests that would need to pass based on that syntax.
lol @seven-phases-max sometimes it's hard to glean what your actual position is.
:) Well, it's just like you start to think of it and come to a conclusion that if it's become too ugly/verbose or too conflicting then at some point you may find yourself preferring something like (already working code):
div {
color: some-ns(primary); // == .some-ns[@primary]
}
.some-ns {
@primary: red;
@secondary: blue;
// etc.
}
// map namespace to function using corresponding plugin:
.function-some-ns(@ident) {
.some-ns;
return: @@ident;
}
which will be sad counting the efforts (to be) taken. So you're keep trying to find better ways (one would expect from the native impl.) till the very end.
Please check out my PR! https://github.com/less/less.js/pull/3242
Question: could we not apply the concept of lookups to lists? That is, why not allow it as a shorthand for:
@items: 1 2 3;
@value: extract(@items, 2); // old
@value: @items[2]; // new
I mean, the evaluation is really not that hard. Most of the work has been done. So, like JavaScript, it could refer to index-based or key-based lookups. The only confusion might be that I think Less lists are 1-based, not 0-based? But I think I would still keep it consistent with whatever extract()
is doing.
Saying @itemsArray: one two three;
is like an "Array" and @itemsObject: { @one:one; @two:two; @three:three; }
is like an "Object" seems like a nice parallel to me. It might be a bit weird, but I can't think of any direct objection, except that we're adding a relationship between two features that weren't all that related. Though the relationship kind of exists, we'd just be formalizing and unifying it.
I think I'd want to deprecate (¿or maybe just discourage?) extract()
in that case, so the question doesn't become "Why can't I extract(@itemsObject, @one)
?".
Got my 👍, but I don't think it's super critical, unless it turns out to be low-hanging fruit.
@calvinjuarez Well it parallelizes other languages like PHP and JavaScript which overlap arrays / maps / objects in the way they're accessed. So yeah, if we imagine every list as having a key/value
, just that flat lists like one two three
, the keys for that are just 1 2 3
(since Less lists are 1-based). So all lists have keys, we just introduce that some are their indices, and some are keywords / names.
except that we're adding a relationship between two features that weren't all that related.
They weren't related, until I started to use rulesets as maps for writing up 3.5 examples. Once you start to think of rulesets as just data, which may produce rules, but may be considered a map of values, then lists start to take on a semantically similar vibe.
What I mean is, in Less, a "list" may just be a property value of a sequence of keywords, or it may be "used" as data for some Less functional purpose. In other words, Less already "re-purposes" CSS structure to produce "data".
Trust me, start using 3.5 syntax and you'll see what I mean lol.
Btw, I ran into this today related to this comment from @seven-phases-max.
To summarize his comment: mixins technically merge their rules together, and that includes their variables. But the values of mixins get evaluated before merge. So even before 3.5, if you wrote:
.mixin() {
@value-1: 1;
@value-2: @value-1;
}
.mixin() {
@value-1: 2;
}
.foo {
.mixin();
bar: @value-2;
}
// output
.foo {
bar: 1;
}
This problem isn't resolved in 3.5, bar: .mixin[@value-2]
would still produce 1
as a value.
To be honest, I don't know that we want to change the behavior, especially with the goal of making vars private in the #16 discussion. But we may need to be careful to document that overriding a value for a variable will not change the computed value of other vars. Instead, users should be encouraged to evaluate the computed values at call time.
I basically "re-discovered" this problem when tinkering with the Less library that I'm using to test out this feature.
@matthew-dean No, no, to reiterate, I have no objections. In my comment I'm stating essentially "Yeah, this all makes a lot of sense". I was thinking inline, though, so it's a little meandering. Sorry about that. I'm on-board.
As to the value evaluation, I think that's a quirk and feature of Less. I'm not sure I'd want it changed.
.mixin() { // default
@var: foo;
}
.mixin() when (@i-want-var-to-be-bar) {
@var: bar;
}
//...
@i-want-var-to-be-bar: true;
.selector {
-less-show: .mixin()[@var];
}
.selector {
-less-show: bar;
}
Right?
Update:
So, then,
.mixin() { // default
@var: foo;
-less-show: @var;
}
.mixin() when (@i-want-var-to-be-bar) {
@var: bar;
}
//...
@i-want-var-to-be-bar: true;
.selector {
.mixin();
}
.selector {
-less-show: bar;
}
They're essentially the same, right?
The discussion around namespacing had some proposals on syntax, but I'm starting to think https://github.com/less/less.js/issues/2767 makes the proposal problematic. https://github.com/less/less.js/issues/1848
Yes, that was part of the namespacing discussion. However, after some of our discussion around unifying mixins and detached ruleset behavior, I'm not sure the syntax really makes sense.
Namespacing
For example, we were talking about:
...with var and prop a variable and property inside that namespace, and the
@
and$
applying to the last identifier. But if we make a detached ruleset a kind of (anonymous mixin assigned to a var), then this logic begins to quickly get confusing.We also talked about the short form
#ns@var
, which becomes something like@dr1@dr2@var
, which conflicts with other syntax.So, I'm thinking for 3.0, we re-think it to one of the earlier suggestions by @lukeapage which was close to the original Ruby syntax with
[]
for properties:That places the
@
symbol closer to the actual variable, and makes the identifier it belongs with less ambiguous.Interpolation
... Discussion moved to #13, as it's not necessary to do both at the same time, or at all.