Skip to content

Commit

Permalink
refactor(expression): update object,assignment and seq expression
Browse files Browse the repository at this point in the history
Added support to get object like string or real key/value pairs
for object and assignment expression
  • Loading branch information
thetutlage committed Mar 27, 2017
1 parent 2004d3e commit 6ebc45a
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 24 deletions.
32 changes: 28 additions & 4 deletions src/Expressions/AssignmentExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,39 @@ class AssignmentExpression extends BaseExpression {
}

/**
* Converts an assignment to an object
* string.
* Returns the key/value pair of assignment as an object
* containing key and value. This method should be used
* when you want to fetch values for individual keys
* at compile time.
*
* For runtime you should consider using `this.toStatement()`
*
* @method toObject
*
* @return {String}
* @return {Object}
*/
toObject () {
return `{${this._convertToStatement(this._tokens.lhs, false)}: ${this._convertToStatement(this._tokens.rhs, true)}}`
return {
key: this._convertToStatement(this._tokens.lhs, false),
value: this._convertToStatement(this._tokens.rhs, true)
}
}

/**
* Converts the expression into a string which looks like
* an object, but is not an object. The `toStatement()`
* should be used when you want to evaluate the object
* at runtime.
*
* For compile time evaluation make use of `this.toObject()` instead.
*
* @method toStatement
*
* @return {String}
*/
toStatement () {
const keyValue = this.toObject()
return `{${keyValue.key}: ${keyValue.value}}`
}
}

Expand Down
36 changes: 32 additions & 4 deletions src/Expressions/ObjectExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ObjectExpression extends BaseExpression {
* @private
*/
_getValue (member) {
return this._convertToStatement(member.value, true)
return member.value.type === 'object' ? member.value.toObject() : this._convertToStatement(member.value, true)
}

/**
Expand All @@ -84,15 +84,43 @@ class ObjectExpression extends BaseExpression {
}

/**
* Converts tokens into parsed statement
* Returns the key/value pair of an object as an array
* containing objects with key and value. This method
* should be used when you want to fetch values for
* individual keys at compile time.
*
* For runtime you should consider using `this.toStatement()`
*
* @method toObject
*
* @return {Array}
*/
toObject () {
return this._tokens.members.map((member) => {
return {
key: this._getKey(member),
value: this._getValue(member)
}
})
}

/**
* Converts the expression into a string which looks like
* an object, but is not an object. The `toStatement()`
* should be used when you want to evaluate the object
* at runtime.
*
* For compile time evaluation make use of `this.toObject()` instead.
*
* @method toStatement
*
* @return {String}
*/
toStatement () {
const convertedMembers = this._tokens.members.map((member) => `${this._getKey(member)}: ${this._getValue(member)}`)
return `{${convertedMembers}}`
const keyValue = this._tokens.members.map((member) => {
return `${this._getKey(member)}: ${this._convertToStatement(member.value, true)}`
})
return `{${keyValue}}`
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/Expressions/SequenceExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,30 @@ class SequenceExpression extends BaseExpression {
}

/**
* Converts tokens into parsed statement
* Converts tokens into a parsed statement. All the
* members `toObject` method is given preference
* over `toStatement` method.
*
* @method toObject
*
* @return {Array}
*/
toObject () {
return this._tokens.members.map((member) => {
return member.toObject ? member.toObject() : member.toStatement()
})
}

/**
* Converts tokens into a parsed statement. All the
* members `toStatement` method is given preference
* over `toObject` method.
*
* @method toStatement
*
* @return {Array}
*/
toStatement () {
return this._tokens.members.map((member) => {
return member.toStatement ? member.toStatement() : member.toObject()
})
Expand Down
18 changes: 15 additions & 3 deletions test/unit/assignment-expression.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,27 @@ test.group('Assignment Expression', (group) => {
assert.equal(this.exp.tokens.rhs.type, 'array')
})

test('convert assignment to object', (assert) => {
test('convert assignment with array to object', (assert) => {
const statement = `users = ['virk', 'nikk']`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.toObject(), `{users: ['virk','nikk']}`)
assert.deepEqual(this.exp.toObject(), {key: 'users', value: `['virk','nikk']`})
})

test('convert assignment with array to statement', (assert) => {
const statement = `users = ['virk', 'nikk']`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toStatement(), `{users: ['virk','nikk']}`)
})

test('convert assignment to object that has identifiers', (assert) => {
const statement = `users = [oldUsers]`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.equal(this.exp.toObject(), `{users: [this.context.resolve('oldUsers')]}`)
assert.deepEqual(this.exp.toObject(), {key: 'users', value: `[this.context.resolve('oldUsers')]`})
})

test('convert assignment to statement that has identifiers', (assert) => {
const statement = `users = [oldUsers]`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toStatement(), `{users: [this.context.resolve('oldUsers')]}`)
})
})
42 changes: 33 additions & 9 deletions test/unit/object-expression.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ test.group('Object Expression', (group) => {
test('convert simple object', (assert) => {
const statement = `a, {name: 'virk'}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{name: 'virk'}`)
assert.deepEqual(this.exp.toObject(), [{key: 'name', value: `'virk'`}])
})

test('parse shorthand object', (assert) => {
Expand All @@ -50,7 +50,7 @@ test.group('Object Expression', (group) => {
test('convert shorthand object', (assert) => {
const statement = `a, {name}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{name: this.context.resolve('name')}`)
assert.deepEqual(this.exp.toObject(), [{key: 'name', value: `this.context.resolve('name')`}])
})

test('parse object with numbers', (assert) => {
Expand All @@ -65,7 +65,7 @@ test.group('Object Expression', (group) => {
test('convert object with numbers', (assert) => {
const statement = `a, {age: 22}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{age: 22}`)
assert.deepEqual(this.exp.toObject(), [{key: 'age', value: 22}])
})

test('parse nested object', (assert) => {
Expand All @@ -79,7 +79,7 @@ test.group('Object Expression', (group) => {
test('convert nested object', (assert) => {
const statement = `a, {profile: { fullname: 'virk' }}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{profile: {fullname: 'virk'}}`)
assert.deepEqual(this.exp.toObject(), [{ key: 'profile', value: [{key: 'fullname', value: `'virk'`}] }])
})

test('parse object with sources on both ends', (assert) => {
Expand All @@ -94,7 +94,7 @@ test.group('Object Expression', (group) => {
test('convert object with sources on both ends', (assert) => {
const statement = `a, { profile: profile }`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{profile: this.context.resolve('profile')}`)
assert.deepEqual(this.exp.toObject(), [{key: 'profile', value: `this.context.resolve('profile')`}])
})

test('parse object with arrays', (assert) => {
Expand All @@ -108,24 +108,48 @@ test.group('Object Expression', (group) => {
test('convert object with arrays', (assert) => {
const statement = `a, {users: ['virk', 'nikk']}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{users: ['virk','nikk']}`)
assert.deepEqual(this.exp.toObject(), [{key: 'users', value: `['virk','nikk']`}])
})

test('convert object with numeric keys', (assert) => {
const statement = `a, {22: 'a'}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{22: 'a'}`)
assert.deepEqual(this.exp.toObject(), [{key: 22, value: `'a'`}])
})

test('convert object with non-standard keys', (assert) => {
const statement = `a, {'full-name': 'virk'}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{'full-name': 'virk'}`)
assert.deepEqual(this.exp.toObject(), [{key: `'full-name'`, value: `'virk'`}])
})

test('convert object with identifier keys', (assert) => {
const statement = `a, {[username]: 'virk'}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.equal(this.exp.toStatement(), `{[this.context.resolve('username')]: 'virk'}`)
assert.deepEqual(this.exp.toObject(), [{key: `[this.context.resolve('username')]`, value: `'virk'`}])
})

test('convert object with mulitple key/value pairs', (assert) => {
const statement = `a, {22: 'a', age: 22}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.deepEqual(this.exp.toObject(), [{key: 22, value: `'a'`}, {key: 'age', value: 22}])
})

test('convert object with non-standard keys to statement', (assert) => {
const statement = `a, {'full-name': 'virk'}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.deepEqual(this.exp.toStatement(), `{'full-name': 'virk'}`)
})

test('convert object with mulitple key/value pairs to statement', (assert) => {
const statement = `a, {22: 'a', age: 22}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.deepEqual(this.exp.toStatement(), `{22: 'a',age: 22}`)
})

test('convert nested object to statement', (assert) => {
const statement = `a, {profile: { fullname: 'virk' }}`
this.exp.parse(esprima.parse(statement).body[0].expression.expressions[1])
assert.deepEqual(this.exp.toStatement(), `{profile: {fullname: 'virk'}}`)
})
})
24 changes: 21 additions & 3 deletions test/unit/sequence-expression.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,36 @@ test.group('Sequence Expression', (group) => {
test('convert sequence to object', (assert) => {
const statement = `'message', { message }`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toObject(), [`'message'`, `{message: this.context.resolve('message')}`])
assert.deepEqual(this.exp.toObject(), [`'message'`, [{key: 'message', value: `this.context.resolve('message')`}]])
})

test('convert sequence to statement', (assert) => {
const statement = `'message', { message }`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toStatement(), [`'message'`, `{message: this.context.resolve('message')}`])
})

test('convert sequence to object with assignment', (assert) => {
const statement = `'message', age = 20`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toObject(), [`'message'`, `{age: 20}`])
assert.deepEqual(this.exp.toObject(), [`'message'`, {key: 'age', value: 20}])
})

test('convert sequence to statement with assignment', (assert) => {
const statement = `'message', age = 20`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toStatement(), [`'message'`, `{age: 20}`])
})

test('convert sequence to object with source as assignment', (assert) => {
const statement = `'message', age = userAge`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toObject(), [`'message'`, `{age: this.context.resolve('userAge')}`])
assert.deepEqual(this.exp.toObject(), [`'message'`, {key: 'age', value: `this.context.resolve('userAge')`}])
})

test('convert sequence to statement with source as assignment', (assert) => {
const statement = `'message', age = userAge`
this.exp.parse(esprima.parse(statement).body[0].expression)
assert.deepEqual(this.exp.toStatement(), [`'message'`, `{age: this.context.resolve('userAge')}`])
})
})

0 comments on commit 6ebc45a

Please sign in to comment.