diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d27245..6838f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Clean up custom element `renderCustomTemplate` function * Add initial reactive variable support * Allow assigning an element to a reference using `:ref` syntax +* Add support for ternary conditionals ## 2.3.19 (2024-04-13) diff --git a/lib/expression/expression.js b/lib/expression/expression.js index 4d1605c..832197a 100644 --- a/lib/expression/expression.js +++ b/lib/expression/expression.js @@ -803,6 +803,17 @@ Expression.setMethod(function getTokenValue(token, vars) { result = this.getObjectLiteralValue(token.object, vars); } else if (token.array) { result = this.getArrayLiteralValue(token.array, vars); + } else if (token.condition) { + + let condition_result = this.parseExpression(token.condition, vars); + + if (this.isTruthy(condition_result)) { + if (token.truthy) { + result = this.parseExpression(token.truthy, vars); + } + } else if (token.falsy) { + result = this.parseExpression(token.falsy, vars); + } } else if (Array.isArray(token)) { result = this.parseExpression(token, vars); } diff --git a/lib/parser/expressions_parser.js b/lib/parser/expressions_parser.js index b5edb98..226d2b9 100644 --- a/lib/parser/expressions_parser.js +++ b/lib/parser/expressions_parser.js @@ -2,7 +2,9 @@ const IN_LITERAL = Symbol('literal'), IN_ARGUMENTS = Symbol('arguments'), IN_OPTIONS = Symbol('options'), IN_PATH_EXPRESSION = Symbol('path_expression'), - IN_EACH_EXPRESSION = Symbol('each_expression'); + IN_EACH_EXPRESSION = Symbol('each_expression'), + IN_CONDITIONAL_TRUE = Symbol('conditional_true'), + IN_CONDITIONAL_FALSE = Symbol('conditional_false'); /** * Expressions parser class: @@ -447,7 +449,7 @@ Eparser.setMethod(function getArguments() { * @since 2.0.0 * @version 2.0.0 * - * @return {Object} + * @return {Object[]} */ Eparser.setMethod(function getArrayLiteral() { @@ -507,7 +509,7 @@ Eparser.setMethod(function getArrayLiteral() { * @since 2.0.0 * @version 2.0.0 * - * @return {Object} + * @return {Object[]} */ Eparser.setMethod(function getObjectLiteral() { @@ -573,17 +575,41 @@ Eparser.setMethod(function getExpressionForEach() { return this.getExpression(0, IN_EACH_EXPRESSION); }); +/** + * Get the conditional expression + * + * @author Jelle De Loecker + * @since 2.4.0 + * @version 2.4.0 + * + * @param {Object|Array} condition + * @param {number} level + * + * @return {Object} + */ +Eparser.setMethod(function getConditionalExpression(condition, level) { + + let truthy = this.getExpression(level, IN_CONDITIONAL_TRUE), + falsy = this.getExpression(level, IN_CONDITIONAL_FALSE); + + return [{ + condition, + truthy, + falsy + }]; +}); + /** * Get expression * * @author Jelle De Loecker * @since 1.2.9 - * @version 2.3.19 + * @version 2.4.0 * * @param {Number} level * @param {Symbol} state Are we in some kind of literal ({}, []) * - * @return {Object} + * @return {Object[]} */ Eparser.setMethod(function getExpression(level, state) { @@ -622,6 +648,20 @@ Eparser.setMethod(function getExpression(level, state) { prev = this.previous_token; entry = result[result.length - 1]; + // See if this is the start of a conditional ternary expression + if (token.value === '?') { + if (!entry) { + throw new Error('Unexpected `?` token'); + } + + // @TODO: make sure there is a colon somewhere? + + this.goToNext(); + let condition = result.pop(); + push('conditional', this.getConditionalExpression(condition, level + 1)); + continue; + } + // Get object literals if (token.value == '{') { this.goToNext(); @@ -640,6 +680,11 @@ Eparser.setMethod(function getExpression(level, state) { break; } + if (state == IN_CONDITIONAL_TRUE && token.value == ':') { + this.goToNext(); + break; + } + if (token.value == '(') { if (prev && !prev.keyword && entry) { diff --git a/test/10-expressions.js b/test/10-expressions.js index 5dafdee..1622ef4 100644 --- a/test/10-expressions.js +++ b/test/10-expressions.js @@ -135,6 +135,22 @@ describe('Expressions', function() { createTests(tests); }); + describe('Conditional', () => { + + let tests = [ + [ + `{{ (c eq "a") ? "A" : "NO" }}`, + `NO` + ], + [ + `{{ (c eq "c") ? "C" : "NO" }}`, + `C` + ] + ]; + + createTests(tests); + }); + describe('Switch', function() { var tests = [ @@ -648,7 +664,7 @@ NO var tests = [ [ `{% block "test" %}TESTING{% /block %}`, - `TESTING` + `TESTING` ], [ `€{% if true %}€{% /if %}`,