Repository: shepherdwind/velocity.js
Pull request #105 (2018-06-10 02:07:14)

Allow mapping values used in set through a function.
This allows me to wrap my objects in a java like classes which gives us better compatibility with java VTL. If this approach is acceptable I will cleanup my PR and add tests.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17410563/badge)](https://coveralls.io/builds/17410563)

Coverage decreased (-0.2%) to 99.035% when pulling **a2ea6ee96dd0adda3934c23ec74c3b26f8d34d6f on lightsofapollo:valueMapper** into **4775b74ed431b3e56a18066b82444fd897a35225 on shepherdwind:master**.

shepherdwind: Thanks for you pr.  You idea is nice.

Patch:
diff --git a/src/compile/index.js b/src/compile/index.js
index dfb5b12..9744a03 100644
--- a/src/compile/index.js
+++ b/src/compile/index.js
@@ -2,13 +2,17 @@ var utils = require('../utils');
 var Helper = require('../helper/index');
 function Velocity(asts, config) {
   this.asts = asts;
-  this.config = {
-    // 自动输出为经过html encode输出
-    escape: true,
-    // 不需要转义的白名单
-    unescape: {}
-  };
-  utils.mixin(this.config, config);
+  this.config = Object.assign(
+    {},
+    {
+      // 自动输出为经过html encode输出
+      escape: true,
+      // 不需要转义的白名单
+      unescape: {},
+      valueMapper: value => value
+    },
+    config
+  );
   this._state = { stop: false, break: false };
   this.init();
 }
diff --git a/src/compile/set.js b/src/compile/set.js
index 8805d7b..5b24709 100644
--- a/src/compile/set.js
+++ b/src/compile/set.js
@@ -1,4 +1,4 @@
-module.exports = function(Velocity, utils){
+module.exports = function(Velocity, utils) {
   /**
    * 变量设置
    */
@@ -6,7 +6,7 @@ module.exports = function(Velocity, utils){
     /**
      * 获取执行环境，对于macro中定义的变量，为局部变量，不贮存在全局中，执行后销毁
      */
-    getContext: function(){
+    getContext: function() {
       var condition = this.condition;
       var local = this.local;
       if (condition) {
@@ -18,9 +18,9 @@ module.exports = function(Velocity, utils){
     /**
      * parse #set
      */
-    setValue: function(ast){
+    setValue: function(ast) {
       var ref = ast.equal[0];
-      var context  = this.getContext();
+      var context = this.getContext();
 
       // @see #25
       if (this.condition && this.condition.indexOf('macro:') === 0) {
@@ -36,7 +36,7 @@ module.exports = function(Velocity, utils){
       if (valAst.type === 'math') {
         val = this.getExpression(valAst);
       } else {
-        val = this.getLiteral(ast.equal[1]);
+        val = this.config.valueMapper(this.getLiteral(ast.equal[1]));
       }
 
       if (!ref.path) {
@@ -54,9 +54,7 @@ module.exports = function(Velocity, utils){
         var len = ref.path ? ref.path.length: 0;
 
         const self = this;
-        //console.log(val);
-        utils.some(ref.path, function(exp, i){
-
+        utils.some(ref.path, function(exp, i) {
           var isEnd = len === i + 1;
           var key = exp.id;
           if (exp.type === 'index')  {


Test patch:
diff --git a/tests/compile.js b/tests/compile.js
index 61ebecb..6c19d50 100644
--- a/tests/compile.js
+++ b/tests/compile.js
@@ -187,6 +187,19 @@ describe('Compile', function() {
       assert.equal('&lt;i&gt;', ret)
     })
 
+    it ('valueMapper support', () => {
+      const values = [];
+      const vm = '#set($foo = "bar")\n$foo'
+      const ret = render(vm, {}, {}, {
+        valueMapper: (value) => {
+          values.push(value);
+          return 'foo';
+        },
+      });
+      assert.deepEqual(values, ['bar']);
+      assert.equal(ret.trim(), 'foo');
+    });
+
     describe('env', function() {
       it('should throw on property when parent is null', function() {
         var vm = '$foo.bar';