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

Nested lists get flattened in javascript evaluation #1939

Closed
phloe opened this issue Mar 27, 2014 · 8 comments
Closed

Nested lists get flattened in javascript evaluation #1939

phloe opened this issue Mar 27, 2014 · 8 comments

Comments

@phloe
Copy link

phloe commented Mar 27, 2014

Using the rest variable (...) I ran into this weird behavior: lists in the rest variable get flattened when passing into a javascript function like in the example below!

Is this behavior intentional? I was not expecting nested lists to get flattened like that.

.mixin (@rest...){
    @sorted: `(function(rest){
        console.log(rest);
        return rest.length;
    }(@{rest}))`;
}

.test {
    .mixin(1, 2, 3; 4, 5; 6);
}

// logs: [1, 2, 3, 4, 5, 6] - yikes!
// expected: [[1, 2, 3], [4, 5], [6]]
// or maybe even: [[1, 2, 3], [4, 5], 6]
@seven-phases-max
Copy link
Member

This issue is somewhat expected since 1, 2, 3; 4, 5; 6 syntax was added later than the variable-in-backticks expansion code (i.e. the latter is simply not adapted to support multidimensional value lists). See https://github.com/less/less.js/blob/v1.7.0/lib/less/tree.js#L44. PRs are welcome ;).

Btw., speaking of multidimensional arrays, don't miss that 1 2 3, 4 5, 6 is also a two-dimensional value list in Less (i.e. I wonder how we expect it to be expanded within a javascript evaluation statement).

@phloe
Copy link
Author

phloe commented Mar 28, 2014

Hmmm, then implementing the behavior I was expecting would most likely be a breaking change. Wonder if this is used anywhere in the real world...

Looks like 1 2 3, 4 5, 6 you mention turns into [1 2 3, 4 5, 6] - which is invalid and throws errors - so turning that into a multidimensional lists in javascript won't be breaking anything :D

@phloe
Copy link
Author

phloe commented Mar 28, 2014

It was almost too easy getting nested lists passed into javascript :) (see https://github.com/rasmusfl0e/less.js/commit/39b366ef790ffa0e899aca6ea26ee4e7db008501)
Going from javascript to less is more problematic though; the level of nesting is limited to 2 by syntax, eg 1 2 3, 4 5, 6 - but deeper nesting is possible through rest variables. Hmmm...

@SomMeri
Copy link
Member

SomMeri commented Mar 29, 2014

I just came to report this :).

Here is my test case:

.mixin(@name, @list) {
    less: @name @list;
    first: @name extract(@list, 1);
    jsfied: @name `'@{list}'`;
}

div-transition {
 @spaced-list: 1 1 1;
 @comma-list: 1, 1, 1;
 @composed-list: @spaced-list, @spaced-list, @spaced-list;

 .mixin(composed, @composed-list);
}

Current output is:

div-transition {
  less: composed 1 1 1, 1 1 1, 1 1 1;
  first: composed 1 1 1;
  jsfied: composed "[1 1 1, 1 1 1, 1 1 1]";
}

I expected this:

div-transition {
  less: composed 1 1 1, 1 1 1, 1 1 1;
  first: composed 1 1 1;
  jsfied: composed "[[1, 1, 1], [1, 1, 1], [1, 1, 1]]";
}

@SomMeri
Copy link
Member

SomMeri commented Mar 29, 2014

@csshat Btw, LessHat relies on current behavior. At minimum their .transition mixin needs to know whether the arguments list was created as space separated or comma separated.

@phloe
Copy link
Author

phloe commented Mar 30, 2014

Yeah - context is important.

Both Less and JS are capable of handling lists/arrays of arbitrary nesting depths - logically.
The problem lies in:

  1. Translating value lists (comma separated) and expression lists (space separated) into arrays for javascript consumption loses value/expression context (important when outputing to Less).
  2. Less(/CSS?) syntax only really supports 1(?) possible structure of nested lists; expression lists nested in an value list. Which means that you can loop through your lists and do crazy stuff all you want - but once you need to output a nested list - there's only one game in town.

It's rather trivial to translate both value/expression lists into arrays for javascript consumption (see 39b366e).
But are there any functions exposed when in javascript to handle value/expression lists? I'm thinking functions that would accept a string, eg 1 1 1, 1 1 1, 1 1 1, and return a meaningful object which could have a toString method that would ensure proper value/expression-list formating when returned to Less...

@seven-phases-max
Copy link
Member

but once you need to output a nested list - there's only one game in town.

Not quite, we still can loop though every item and output through +: and +_: (though all this goes quite verbose) and/or use whatever custom delimiter (with ~"" after all).

P.S.

Less(/CSS?) syntax only really supports 1(?) possible structure of nested lists; expression lists nested in an value list.

Nope as well, consider this example:

@a: 1 2 3;
@b: a b c;
@c: x, y, z;
@d: @a, @b @c;
@e: @d @d;

div {.some-mixin(@a @b, @c, @d; @e;)}

.some-mixin(@list...) {
    hello-multiverse: @list;
}

I.e. technically any "type" (i.e. , or ) of array may contain values of any type of array.

@seven-phases-max
Copy link
Member

I.e. technically any "type" (i.e. , or ) of array may contain values of any type of array.

Which of course does not cancel the fact that in context of CSS a space separated list containing a comma separated list does not make any sense (i.e. only 1 2, 3 4, 5 6 -> [[1, 2], [3, 4], [5, 6]] and vice-versa is reasonable), so in a perfect world a more elegant/generic method to handle such things in a library seems to be to interpret lowest level array as space separated list and higher level array(s) as comma-separated one (if the function/mixin expects multidimensional array as parameter(s) or returns it).

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

No branches or pull requests

5 participants