Skip to content

Commit

Permalink
feat(set): add set tag
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Jul 7, 2018
1 parent 772cdb7 commit 81dcae8
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 61 deletions.
7 changes: 7 additions & 0 deletions fixtures/set-tag-identifier/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(function (template, ctx) {
let out = ''
ctx.set('username', ctx.resolve('username').split('')[0])
out += `${ctx.escape(ctx.resolve('username'))}`
out += '\n'
return out
})(template, ctx)
2 changes: 2 additions & 0 deletions fixtures/set-tag-identifier/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@set('username', username.split('')[0])
{{ username }}
3 changes: 3 additions & 0 deletions fixtures/set-tag-identifier/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"username": "virk"
}
1 change: 1 addition & 0 deletions fixtures/set-tag-identifier/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v
7 changes: 7 additions & 0 deletions fixtures/set-tag/compiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(function (template, ctx) {
let out = ''
ctx.set('username', 'nikk')
out += `${ctx.escape(ctx.resolve('username'))}`
out += '\n'
return out
})(template, ctx)
2 changes: 2 additions & 0 deletions fixtures/set-tag/index.edge
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@set('username', 'nikk')
{{ username }}
3 changes: 3 additions & 0 deletions fixtures/set-tag/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"username": "virk"
}
1 change: 1 addition & 0 deletions fixtures/set-tag/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nikk
59 changes: 3 additions & 56 deletions src/Tags/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,14 @@
import { Parser } from 'edge-parser'
import { EdgeBuffer } from 'edge-parser/build/src/EdgeBuffer'
import { IBlockNode } from 'edge-lexer/build/src/Contracts'
import { UnAllowedExpressionException, TooManyArgumentsException } from '../Exceptions'
import { parseSequenceExpression, ObjectifyString } from '../utils'
import { parseSequenceExpression, ObjectifyString, parseAsKeyValuePair } from '../utils'

export class ComponentTag {
public static block = true
public static seekable = true
public static selfclosed = true
public static tagName = 'component'

/**
* Returns the slot name and the slot prop name.
*/
private _getNameAndPropsName (statement: IBlockNode, parser: Parser): [string, string | null] {
const ast = parser.generateAst(statement.properties.jsArg, statement.lineno)
const expression = ast.body[0].expression

/**
* Return without counting props, value is a literal
*/
if (expression.type === 'Literal') {
return [expression.raw, null]
}

/**
* Raise error when not a sequence expression
*/
if (expression.type !== 'SequenceExpression') {
throw UnAllowedExpressionException.invoke('slot', expression.type, expression.loc.start.line)
}

/**
* Raise error when more than 2 arguments are passed to the slot
* expression
*/
if (expression.expressions.length > 2) {
throw TooManyArgumentsException.invoke('slot', 2, expression.loc.start.line)
}

/**
* Raise error when first expression or sequence expressions is not a literal.
* Since slot name must be a string
*/
if (expression.expressions[0].type !== 'Literal') {
throw UnAllowedExpressionException
.invoke('slot', expression.expressions[0].type, expression.expressions[0].loc.start.line)
}

/**
* Raise error when 2nd expression of the sequence expressions is not an indentifier.
* Since slot prop has to be an identifier
*/
if (expression.expressions[1].type !== 'Identifier') {
throw UnAllowedExpressionException
.invoke('slot', expression.expressions[1].type, expression.expressions[1].loc.end.line)
}

/**
* Finally return the name and prop name for the slot
*/
return [expression.expressions[0].raw, expression.expressions[1].name]
}

/**
* Compiles else block node to Javascript else statement
*/
Expand All @@ -87,7 +33,8 @@ export class ComponentTag {
let slotProps: string | null = null

if (child.type === 'block' && (child as IBlockNode).properties.name === 'slot') {
const parsed = this._getNameAndPropsName((child as IBlockNode), parser)
const statement = parser.generateAst((child as IBlockNode).properties.jsArg, child.lineno)
const parsed = parseAsKeyValuePair(statement.body[0].expression, parser, ['Identifier'])
slotName = parsed[0]
slotProps = parsed[1]
}
Expand Down
29 changes: 29 additions & 0 deletions src/Tags/Set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 { parseAsKeyValuePair } from '../utils'

export class SetTag {
public static block = false
public static seekable = true
public static selfclosed = false
public static tagName = 'set'

/**
* Compiles else block node to Javascript else statement
*/
public compile (parser: Parser, buffer: EdgeBuffer, token: IBlockNode) {
const ast = parser.parseJsArg(token.properties.jsArg, token.lineno)
const [key, value] = parseAsKeyValuePair(ast, parser, [])
buffer.writeStatement(`ctx.set(${key}, ${value})`)
}
}
1 change: 1 addition & 0 deletions src/Tags/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { EachTag as each } from './Each'
export { ComponentTag as component } from './Component'
export { SlotTag as slot } from './Slot'
export { DebuggerTag as debugger } from './Debugger'
export { SetTag as set } from './Set'
54 changes: 51 additions & 3 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/

import { UnAllowedExpressionException } from '../Exceptions'
import { UnAllowedExpressionException, TooManyArgumentsException } from '../Exceptions'
import { Parser } from 'edge-parser'
import { sep } from 'path'

Expand Down Expand Up @@ -38,7 +38,7 @@ export class ObjectifyString {
*/
export function allowExpressions (tag: string, expression: any, expressions: string[]) {
if (expressions.indexOf(expression.type) === -1) {
throw UnAllowedExpressionException.invoke('if', expression.type, expression.loc.start.line)
throw UnAllowedExpressionException.invoke(tag, expression.type, expression.loc.start.line)
}
}

Expand All @@ -48,7 +48,7 @@ export function allowExpressions (tag: string, expression: any, expressions: str
*/
export function disAllowExpressions (tag: string, expression: any, expressions: string[]) {
if (expressions.indexOf(expression.type) > -1) {
throw UnAllowedExpressionException.invoke('if', expression.type, expression.loc.start.line)
throw UnAllowedExpressionException.invoke(tag, expression.type, expression.loc.start.line)
}
}

Expand Down Expand Up @@ -98,6 +98,54 @@ export function parseSequenceExpression (expression: any, parser: Parser): [stri
return [name, `{}`]
}

/**
* Parses an expression as a key/value pair and has following constraints.
*
* 1. Top level expression must be `Literal` or `SequenceExpression`.
* 2. If `SequenceExpression`, then first child of expression must be `Literal`
* 3. Length of `SequenceExpression` childs must be 2 at max.
*
* Optionally, you can enforce (3rd argument) that value in the key/value pair must be one
* of the given expressions.
*
* ```
* // Following are the valid expressions
* ('foo', 'bar')
* ('foo')
* ('foo', bar)
* ('foo', { bar: true })
* ```
*/
export function parseAsKeyValuePair (expression: any, parser: Parser, valueExpressions: string[]): [string, null | string] {
allowExpressions('slot', expression, ['Literal', 'SequenceExpression'])

/**
* Return without counting props, value is a literal
*/
if (expression.type === 'Literal') {
return [expression.raw, null]
}

/**
* Raise error when more than 2 arguments are passed to the slot
* expression
*/
if (expression.expressions.length > 2) {
throw TooManyArgumentsException.invoke('slot', 2, expression.loc.start.line)
}

allowExpressions('slot', expression.expressions[0], ['Literal'])

if (valueExpressions.length) {
allowExpressions('slot', expression.expressions[1], valueExpressions)
}

/**
* Finally return the name and prop name for the slot
*/
return [expression.expressions[0].raw, parser.statementToString(expression.expressions[1])]
}

/**
* Extracts the disk name and the template name from the template
* path expression.
Expand Down
4 changes: 2 additions & 2 deletions test/tags.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ test.group('Include', (group) => {
compiler.compile('foo', true)
} catch (error) {
assert.equal(error.line, 1)
assert.equal(error.message, 'E_UNALLOWED_EXPRESSION: SequenceExpression is not allowed for if tag\n> More details: https://err.sh/poppinss/edge-errors/E_UNALLOWED_EXPRESSION')
assert.equal(error.message, 'E_UNALLOWED_EXPRESSION: SequenceExpression is not allowed for include tag\n> More details: https://err.sh/poppinss/edge-errors/E_UNALLOWED_EXPRESSION')
}
})
})
Expand Down Expand Up @@ -189,7 +189,7 @@ test.group('Component', (group) => {
try {
compiler.compile('foo', true)
} catch (error) {
assert.equal(error.line, 5)
assert.equal(error.line, 3)
assert.equal(error.message, 'E_UNALLOWED_EXPRESSION: Literal is not allowed for slot tag\n> More details: https://err.sh/poppinss/edge-errors/E_UNALLOWED_EXPRESSION')
}
})
Expand Down

0 comments on commit 81dcae8

Please sign in to comment.