Skip to content

Commit

Permalink
feat(expression): add support for conditional expression
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 22, 2017
1 parent 8eb86c9 commit 6b6d1d2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
108 changes: 108 additions & 0 deletions src/Expressions/ConditionalExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict'

/*
* 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.
*/

const BaseExpression = require('./BaseExpression')

/**
* Conditional expression parses the shorthand if
* statement.
*
* @class ConditionalExpression
* @extends {BaseExpression}
* @constructor
*
* @example
* ```js
* username ? username : 'anonymous'
* ```
*
*/
class ConditionalExpression extends BaseExpression {
constructor (lexer) {
super(lexer)
this._tokens = {
members: [],
test: null,
consequent: null,
alternate: null,
wrapAlternate: false,
type: 'conditional'
}
}

/**
* Parses the expression. It is responsibility of the
* consumer to pass the right expression otherwise
* things will blow.
*
* @method parse
*
* @param {Object} expression
*
* @return {void}
*/
parse (expression) {
this._tokens.test = this._lexer.parse(expression.test)
this._tokens.consequent = this._lexer.parse(expression.consequent)
this._tokens.alternate = this._lexer.parse(expression.alternate)
this._tokens.wrapAlternate = expression.alternate.type === 'ConditionalExpression'
}

/**
* Returns the formatted string for the alternate part
* of the token
*
* @method testStatement
*
* @return {String}
*/
testStatement () {
return this._convertToStatement(this._tokens.test, true)
}

/**
* Returns the formatted string for the alternate part
* of the token
*
* @method consequentStatement
*
* @return {String}
*/
consequentStatement () {
return this._convertToStatement(this._tokens.consequent, true)
}

/**
* Returns the formatted string for the alternate part
* of the token
*
* @method alternateStatement
*
* @return {String}
*/
alternateStatement () {
const alternateStatement = this._convertToStatement(this._tokens.alternate, true)
return this._tokens.wrapAlternate ? `(${alternateStatement})` : alternateStatement
}

/**
* Converts tokens into parsed statement
*
* @method toStatement
*
* @return {String}
*/
toStatement () {
return `${this.testStatement()} ? ${this.consequentStatement()} : ${this.alternateStatement()}`
}
}

module.exports = ConditionalExpression
3 changes: 2 additions & 1 deletion src/Expressions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ module.exports = {
AssignmentExpression: require('./AssignmentExpression'),
CallExpression: require('./CallExpression'),
UnaryExpression: require('./UnaryExpression'),
LogicalExpression: require('./LogicalExpression')
LogicalExpression: require('./LogicalExpression'),
ConditionalExpression: require('./ConditionalExpression')
}
53 changes: 53 additions & 0 deletions test/unit/conditional-expression.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict'

/*
* 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.
*/

const test = require('japa')
const esprima = require('esprima')
const Lexer = require('../../src/Lexer')
const ConditionalExpression = require('../../src/Expressions').ConditionalExpression
const expressionsMixin = require('../../test-helpers/expression-mixin')

test.group('Conditional Expression', (group) => {
group.beforeEach(() => {
this.exp = new ConditionalExpression(new Lexer())
})

expressionsMixin.bind(this)(test)

test('parse simple if shorthand', (assert) => {
const statement = `username ? username : 'anonymous'`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.tokens.test.type, 'source')
assert.equal(this.exp.tokens.test.value, 'username')
assert.equal(this.exp.tokens.consequent.type, 'source')
assert.equal(this.exp.tokens.consequent.value, 'username')
assert.equal(this.exp.tokens.alternate.type, 'string')
assert.equal(this.exp.tokens.alternate.value, 'anonymous')
})

test('convert simple if shorthand', (assert) => {
const statement = `username ? username : 'anonymous'`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.toStatement(), `this.context.resolve('username') ? this.context.resolve('username') : 'anonymous'`)
})

test('convert if shorthand with logical operator', (assert) => {
const statement = `username === 'virk' ? username : 'anonymous'`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.toStatement(), `this.context.resolve('username') === 'virk' ? this.context.resolve('username') : 'anonymous'`)
})

test('convert if shorthand with nested logical operator', (assert) => {
const statement = `username ? username : (session ? session.username : 'anonymous')`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.toStatement(), `this.context.resolve('username') ? this.context.resolve('username') : (this.context.resolve('session') ? this.context.accessChild(this.context.resolve('session'), ['username']) : 'anonymous')`)
})
})

0 comments on commit 6b6d1d2

Please sign in to comment.