Repository navigation
fix(pug-code-gen): evaluate each iterable before scoping loop variables - #3483
cdytotoro-ctrl wants to merge 1 commit into
Conversation
The generated code for 'each val in expr' evaluated expr inside the same function scope where the loop body declares 'var val' and 'var index'. Because of var hoisting, the loop variable declarations shadow outer variables of the same name with undefined while expr is evaluated, so a nested 'each val, index in val.length > 1 ? val[1] : []' crashed with 'Cannot read property length of undefined' (Fixes pugjs#2733). The iterable expression is now passed as an argument of the scoping IIFE, so it is evaluated in the enclosing scope (where outer 'val' and 'index' are still live) while the loop body keeps its own scoped variables. The expression is parenthesized so top-level comma expressions still work as a single argument. Fixes pugjs#2733
|
There is no change log for this pull request yet. |
|
Thanks for this! I tested it against master ( The fix is right. On master and 3.0.4, #2733's template throws
Unchanged from master: Tests:
Two behaviour changes worth knowing, both because the iterable is now evaluated in the template function rather than inside the IIFE. Neither needs a change in my view:
Out of scope here, but the same defect: Rolling Versions still says there is no changelog entry. Something like this for Looks good to merge to me. |
The generated code for 'each val in expr' evaluated expr inside the same function scope where the loop body declares 'var val' and 'var index'. Because of var hoisting, the loop variable declarations shadowed outer variables of the same name with undefined while expr was evaluated, so a nested 'each val, index in val.length > 1 ? val[1] : []' crashed with 'Cannot read property length of undefined' (Fixes #2733).
The iterable expression is now passed as an argument of the scoping IIFE, so it is evaluated in the enclosing scope (where outer 'val' and 'index' are still live) while the loop body keeps its own scoped variables. The expression is parenthesized so top-level comma expressions still work as a single argument.
Tests: new test case nested-each-shadowing reproduces the issue example; existing each/eachOf/alternate cases all pass.