Skip to content

Commit

Permalink
feat(tag): each
Browse files Browse the repository at this point in the history
implement each tag
  • Loading branch information
thetutlage committed Jul 4, 2018
1 parent 79800b9 commit f8d6d02
Show file tree
Hide file tree
Showing 28 changed files with 319 additions and 47 deletions.
17 changes: 17 additions & 0 deletions fixtures/each-tag-array/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(function (template, ctx) {
let out = ''
ctx.loop([{
username: 'virk'
}], function (user, key) {
ctx.newFrame()
ctx.setOnFrame('user', user)
ctx.setOnFrame('key', key)
out += '\n'
out += ' - Hello '
out += `${ctx.escape(ctx.resolve('user').username)}`
out += '\n'
ctx.removeFrame()
})
out += '\n'
return out
})(template, ctx)
3 changes: 3 additions & 0 deletions fixtures/each-tag-array/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@each(user in [{ username: 'virk' }])
- Hello {{ user.username }}
@endeach
1 change: 1 addition & 0 deletions fixtures/each-tag-array/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions fixtures/each-tag-array/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Hello virk
21 changes: 21 additions & 0 deletions fixtures/each-tag-else/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(function (template, ctx) {
let out = ''
if(ctx.size(ctx.resolve('users'))) {
ctx.loop(ctx.resolve('users'), function (user, key) {
ctx.newFrame()
ctx.setOnFrame('user', user)
ctx.setOnFrame('key', key)
out += '\n'
out += ' - Hello '
out += `${ctx.escape(ctx.resolve('user').username)}`
out += '\n'
ctx.removeFrame()
})
} else {
out += '\n'
out += ' No users found'
out += '\n'
}
out += '\n'
return out
})(template, ctx)
5 changes: 5 additions & 0 deletions fixtures/each-tag-else/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@each(user in users)
- Hello {{ user.username }}
@else
No users found
@endeach
2 changes: 2 additions & 0 deletions fixtures/each-tag-else/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
1 change: 1 addition & 0 deletions fixtures/each-tag-else/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No users found
15 changes: 15 additions & 0 deletions fixtures/each-tag-index/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(function (template, ctx) {
let out = ''
ctx.loop(ctx.resolve('users'), function (user, index) {
ctx.newFrame()
ctx.setOnFrame('user', user)
ctx.setOnFrame('index', index)
out += '\n'
out += ' - Hello '
out += `${ctx.escape(ctx.resolve('user').username)}`
out += '\n'
ctx.removeFrame()
})
out += '\n'
return out
})(template, ctx)
3 changes: 3 additions & 0 deletions fixtures/each-tag-index/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@each((user, index) in users)
- Hello {{ user.username }}
@endeach
5 changes: 5 additions & 0 deletions fixtures/each-tag-index/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"users": [{
"username": "virk"
}]
}
1 change: 1 addition & 0 deletions fixtures/each-tag-index/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Hello virk
15 changes: 15 additions & 0 deletions fixtures/each-tag/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(function (template, ctx) {
let out = ''
ctx.loop(ctx.resolve('users'), function (user, key) {
ctx.newFrame()
ctx.setOnFrame('user', user)
ctx.setOnFrame('key', key)
out += '\n'
out += ' - Hello '
out += `${ctx.escape(ctx.resolve('user').username)}`
out += '\n'
ctx.removeFrame()
})
out += '\n'
return out
})(template, ctx)
3 changes: 3 additions & 0 deletions fixtures/each-tag/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@each(user in users)
- Hello {{ user.username }}
@endeach
5 changes: 5 additions & 0 deletions fixtures/each-tag/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"users": [{
"username": "virk"
}]
}
1 change: 1 addition & 0 deletions fixtures/each-tag/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Hello virk
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
},
"dependencies": {
"deep-extend": "^0.6.0",
"edge-parser": "^1.0.5",
"edge-parser": "^1.0.7",
"he": "^1.1.1",
"macroable": "^1.0.0",
"node-exceptions": "^3.0.0"
Expand Down
8 changes: 4 additions & 4 deletions src/Exceptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import * as NE from 'node-exceptions'
const errShLink = 'poppinss/edge-errors'

class BaseException extends NE.LogicalException {
public loc: any
constructor (message, status, code, link) {
public line: number
constructor (message: string, status: number, code: string, link: string) {
super(message, status, code, link)
}
}

export class UnAllowedExpressionException extends BaseException {
public static invoke (tag, expression, loc) {
public static invoke (tag: string, expression: string, line: number) {
const message = `${expression} is not allowed for ${tag} tag`
const error = new this(message, 500, 'E_UNALLOWED_EXPRESSION', errShLink)
error.loc = loc
error.line = line

throw error
}
Expand Down
25 changes: 0 additions & 25 deletions src/Tags/BaseTag.ts

This file was deleted.

135 changes: 135 additions & 0 deletions src/Tags/Each.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* edge
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { Parser } from 'edge-parser'
import { EdgeBuffer } from 'edge-parser/build/src/EdgeBuffer'
import { IBlockNode } from 'edge-lexer/build/src/Contracts'
import { allowExpressions } from '../utils'
import { each, size as lodashSize } from 'lodash'

export class EachTag {
public static block = true
public static seekable = true
public static selfclosed = true

private allowedExpressions = ['BinaryExpression']

/**
* Returns the value and key names for the foreach loop
*/
private _getLoopKeyValue (expression: any): [string, string] {
allowExpressions('each', expression, ['SequenceExpression', 'Identifier'])

if (expression.type === 'SequenceExpression') {
return [expression.expressions[0].name, expression.expressions[1].name]
}

return [expression.name, 'key']
}

private _getLoopSource (expression: any, parser: Parser): string {
return parser.statementToString(parser.parseStatement(expression))
}

/**
* Compiles else block node to Javascript else statement
*/
public compile (parser: Parser, buffer: EdgeBuffer, token: IBlockNode) {
const ast = parser.generateAst(token.properties.jsArg, token.lineno)
const expression = ast.body[0].expression

allowExpressions('each', expression, this.allowedExpressions)

const [value, key] = this._getLoopKeyValue(expression.left)
const rhs = this._getLoopSource(expression.right, parser)

const elseIndex = token
.children
.findIndex((child) => {
return child.type === 'block' && (child as IBlockNode).properties.name === 'else'
})
const elseChild = elseIndex > -1 ? token.children.splice(elseIndex) : []

/**
* If there is an else statement, then wrap the loop
* inside the `if` statement first
*/
if (elseIndex > -1) {
buffer.writeStatement(`if(ctx.size(${rhs})) {`)
buffer.indent()
}

/**
* Write the loop statement to the template
*/
buffer.writeStatement(`ctx.loop(${rhs}, function (${value}, ${key}) {`)

/**
* Indent block
*/
buffer.indent()

/**
* Start a new context frame. Frame ensures the value inside
* the loop is given priority over top level values. Think
* of it as a Javascript block scope.
*/
buffer.writeStatement('ctx.newFrame()')

/**
* Set key and value pair on the context
*/
buffer.writeStatement(`ctx.setOnFrame('${value}', ${value})`)
buffer.writeStatement(`ctx.setOnFrame('${key}', ${key})`)

/**
* Process all kids
*/
token.children.forEach((child, index) => {
parser.processToken(child, buffer)
})

/**
* Remove the frame
*/
buffer.writeStatement('ctx.removeFrame()')

/**
* Dedent block
*/
buffer.dedent()

/**
* Close each loop
*/
buffer.writeStatement('})')

/**
* If there is an else statement, then process
* else childs and close the if block
*/
if (elseIndex > -1) {
elseChild.forEach((child) => parser.processToken(child, buffer))
buffer.dedent()
buffer.writeStatement(`}`)
}
}

public static run (Context) {
Context.macro('loop', function loop (source, callback) {
each(source, (value, key) => {
callback(value, key)
})
})

Context.macro('size', function size (source) {
return lodashSize(source)
})
}
}
17 changes: 14 additions & 3 deletions src/Tags/ElseIf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
import { Parser } from 'edge-parser'
import { EdgeBuffer } from 'edge-parser/build/src/EdgeBuffer'
import { IBlockNode } from 'edge-lexer/build/src/Contracts'
import { BaseTag } from './BaseTag'
import { disAllowExpressions } from '../utils'

export class ElseIfTag extends BaseTag {
export class ElseIfTag {
public static block = false
public static seekable = true
public static selfclosed = false
Expand All @@ -24,10 +24,21 @@ export class ElseIfTag extends BaseTag {
*/
public compile (parser: Parser, buffer: EdgeBuffer, token: IBlockNode) {
const parsed = parser.parseJsArg(token.properties.jsArg, token.lineno)
this._validateExpression(parsed, token.lineno)
disAllowExpressions('elseif', parsed, this.bannedExpressions)

/**
* Dedent block
*/
buffer.dedent()

/**
* Start else block
*/
buffer.writeStatement(`} else if(${parser.statementToString(parsed)}) {`)

/**
* Indent block again
*/
buffer.indent()
}
}
Loading

0 comments on commit f8d6d02

Please sign in to comment.