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

Less_Parser::getVariables doesn't return variables from imported files #47

Open
gavinlimely opened this issue Sep 14, 2020 · 1 comment
Labels
Type: Enhancement New feature or request

Comments

@gavinlimely
Copy link

Is there a way you can do this?

@Krinkle Krinkle added the Type: Question Ask for help, and other questions label Aug 9, 2021
@Krinkle
Copy link
Member

Krinkle commented Aug 14, 2023

I've investigated this today, and conclude the following:

Less_Parser::getVariables iterates on $this->rules which is an array of rules as collected during the initial parse() or parseFiles() calls. These are not yet compiled, and thus will include @import as unprocessed node at this point.

The documention of the original less.php project makes mention of the requirement to call getCSS() before calling getVariables() so that values that have non-literal values (e.g. composed of other variables, or that use a calculation or expression of some kind, or are imported from other files) can be seen.

When getCSS() performs the compilation, it creates a new tree ($evaldRoot). As such, the rules that are being iterated by getVariables() continue to reflect only the direct assignments in the top-level parsed files or content.

I explored a few ways to making this work:

  • Assign $evaldRoot to an instance member before the end of getCSS(), and update getVariables() to iterate $this->evaldRoot->rules instead of $this->rules. This doesn't work because compilation phase not only evaluates and flattens imported files and computed expressions in variable values, the Less_Visitor_toCSS post visitor also effectively discards and removes any trace of the Less_Tree_Variable objects or their transformed Less_Tree_Rule->variable === true equivalents, because they produce no CSS output.
  • Track variables in the Less_Environment object. This is actually already done. When the compiler finds an expression in Less that refers to a variable, that reference is represented by Less_Tree_Variable and Less_Tree_Variable::compileuses$env->frames[…]->variable()to find a matching value. But, by the timegetCSS()is done,Environment->$frame` is empty. This makes sense because the compiler is no longer inside any file context, and the Less specification requires variables to depend on lexical scope. Variables may be limited to particular files or rulesets only. So when we are no longer in a file, there are no longer any variables in scope.
  • Keep track of the last frame in Less_Environment before we shift it out of memory. Or, alternatively, assign $evaldRoot before the Less_Visitor_toCSS phase happens in getCSS(). Both of these approaches would result in us keeping a reference to the expanded Tree which at that point in time has all the variable values in the global scope, and has not yet discarded these as part of producing CSS output. The problem with this approach is that Less_Visitor_toCSS actually modifies the tree in-place. While the compiler takes care to keep the compiled and original rules tree separate, it has no reason for internal compilation steps to not simply do the most optimal thing and modify the tree in-place. This means by the time getCSS() is finished, there are no longer redundant things in the tree such as Less_Tree_Rule objects that represent variable assignments.

@Krinkle Krinkle added Type: Enhancement New feature or request and removed Type: Question Ask for help, and other questions labels Feb 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement New feature or request
Development

No branches or pull requests

2 participants