docs: function parseProp (node, d, key, result, propKey) {
    var prevVal = node.prevVal;
    var lastVal = node.lastVal;
  
    // the prop name get from object key or candidate key
    var propName = isNumeric(key) ? propKey : key;
  
    // NEXT: propName can be changed by user
    // now it's not used, since propName ensure exists
    // corner case: propKey==='' ?? below line will do wrong!!
    // if(!propName) return
  
    var raw = node.lastRaw[propName],
        prev = prevVal && prevVal[propName],
        argObj = {node:node, result:result};
  
    if (raw) argObj.raw = raw[0];
  
    ![].concat(d[key]).forEach(function (v) {
      // prepare value function args
      argObj.cooked = prev;
  
      // pass lastVal if it's function
      argObj.raw = raw = isFunction(v)
          ? v(argObj)
          : v;
  
      var val = applyPlugins(result.config, 'value', raw, propName, node, result, propKey);
  
      // check and merge only format as Object || Array of Object, other format not accepted!
      if (isIterable(val)) {
        for (var k in val) {
          if (own(val, k)) parseProp(node, val, k, result, propName);
        }
      } else {
        arrayKV (
          node.rawVal,
          propName,
          raw,
          true
        );
        if (isValidCSSValue(val)) {
          // only valid val can enter node.prop and lastVal
          // push every val to prop
          arrayKV(
            node.prop,
            propName,
            val,
            true
          );
          prev = lastVal[propName] = val;
        }
      }
    });
    if (prevVal) {
      if (!(propName in prevVal)) {
        arrayKV(node.diff, 'added', propName);
      } else if (prevVal[propName] != lastVal[propName]) {
        arrayKV(node.diff, 'changed', propName);
      }
    }
  }