Skip to content

Commit

Permalink
fix(tags): allow nested each loops
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 18, 2017
1 parent 4e27261 commit 47ebd9c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
5 changes: 4 additions & 1 deletion src/Tags/EachTag.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ class EachTag extends BaseTag {
buffer.indent()
}

const varName = parser.runtimeVariable('payload')
buffer.writeLine(`const ${varName} = ${rhs}`)

/**
* Create a new frame before running the
* each loop.
Expand All @@ -132,7 +135,7 @@ class EachTag extends BaseTag {
/**
* Write the actual each loop
*/
buffer.writeLine(`this.context.loop(${rhs}, (${itteratorName}, loop) => {`)
buffer.writeLine(`this.context.loop(${varName}, (${itteratorName}, loop) => {`)
buffer.indent()

/**
Expand Down
15 changes: 15 additions & 0 deletions src/Template/Compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class TemplateCompiler {
this._processedLines = {}
this._loader = loader
this.buffer = new InternalBuffer(asFunction)
this._runtimeVarIndex = 0
}

/**
Expand Down Expand Up @@ -203,6 +204,20 @@ class TemplateCompiler {
debug('compiled template to %s', output)
return output
}

/**
* Get a unique runtime variable for a given template
*
* @method runtimeVariable
*
* @param {String} [prefix = 'var']
*
* @return {String}
*/
runtimeVariable (prefix = 'var') {
this._runtimeVarIndex++
return `${prefix}_${this._runtimeVarIndex}`
}
}

module.exports = TemplateCompiler
47 changes: 41 additions & 6 deletions test/unit/tags/each.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

const _ = require('lodash')
const test = require('japa')
const Template = require('../../../src/Template')
const TemplateRunner = require('../../../src/Template/Runner')
Expand All @@ -22,8 +23,9 @@ test.group('Tags | Each ', (group) => {
assert.equal(output, dedent`
return (function templateFn () {
let out = new String()
const payload_1 = this.context.resolve('users')
this.context.newFrame()
this.context.loop(this.context.resolve('users'), (user, loop) => {
this.context.loop(payload_1, (user, loop) => {
this.context.setOnFrame('user', user)
this.context.setOnFrame('$loop', loop)
})
Expand All @@ -44,8 +46,9 @@ test.group('Tags | Each ', (group) => {
assert.equal(output, dedent`
return (function templateFn () {
let out = new String()
const payload_1 = this.context.resolve('users')
this.context.newFrame()
this.context.loop(this.context.resolve('users'), (user, loop) => {
this.context.loop(payload_1, (user, loop) => {
this.context.setOnFrame('user', user)
this.context.setOnFrame('$loop', loop)
out += \` <p> Hello \${this.context.escape(this.context.accessChild(this.context.resolve('user'), ['username']))} </p>\\n\`
Expand All @@ -65,8 +68,9 @@ test.group('Tags | Each ', (group) => {
`
const template = new Template(this.tags)
const output = template.compileString(statement).split('\n')
assert.equal(output[3].trim(), `this.context.loop(this.context.resolve('users'), (user, loop) => {`)
assert.equal(output[7].trim(), `this.context.loop(this.context.accessChild(this.context.resolve('user'), ['profiles']), (profile, loop) => {`)
assert.equal(output[4].trim(), `this.context.loop(payload_1, (user, loop) => {`)
assert.equal(output[7].trim(), `const payload_2 = this.context.accessChild(this.context.resolve('user'), ['profiles'])`)
assert.equal(output[9].trim(), `this.context.loop(payload_2, (profile, loop) => {`)
})

test('throw exception when expression is not binary', (assert) => {
Expand Down Expand Up @@ -110,8 +114,9 @@ test.group('Tags | Each ', (group) => {
assert.equal(output, dedent`
return (function templateFn () {
let out = new String()
const payload_1 = this.context.resolve('users')
this.context.newFrame()
this.context.loop(this.context.resolve('users'), (user, loop) => {
this.context.loop(payload_1, (user, loop) => {
this.context.setOnFrame('user', user)
this.context.setOnFrame('$loop', loop)
this.context.setOnFrame('index', loop.key)
Expand Down Expand Up @@ -201,8 +206,9 @@ test.group('Tags | Each ', (group) => {
return (function templateFn () {
let out = new String()
if (this.context.hasLength(this.context.resolve('users'))) {
const payload_1 = this.context.resolve('users')
this.context.newFrame()
this.context.loop(this.context.resolve('users'), (user, loop) => {
this.context.loop(payload_1, (user, loop) => {
this.context.setOnFrame('user', user)
this.context.setOnFrame('$loop', loop)
out += \` \${this.context.escape(this.context.accessChild(this.context.resolve('user'), ['username']))}\\n\`
Expand Down Expand Up @@ -235,4 +241,33 @@ test.group('Tags | Each ', (group) => {
}).run()
assert.equal(output.trim(), '<p> No users found </p>')
})

test('parse nested loop', (assert) => {
const statement = dedent`
@each(users in usersGroup)
@each(user in users)
{{ user.username }}
@endeach
@else
<p> No users found </p>
@endeach
`
const template = new Template(this.tags).compileString(statement)
this.tags.each.run(Context)

const users = [{username: 'virk'}, {username: 'nikk'}]

const ctx = new Context('', {
usersGroup: _.chunk(users, 2)
})

const output = new TemplateRunner(template, {
context: ctx
}).run()

assert.equal(output.trim(), dedent`
virk
nikk
`)
})
})

0 comments on commit 47ebd9c

Please sign in to comment.