var hasOwnProperty = Object.prototype.hasOwnProperty; var shape = { generic: true, types: {}, properties: {}, parseContext: {}, scope: {}, atrule: ['parse'], pseudo: ['parse'], node: ['name', 'structure', 'parse', 'generate', 'walkContext'] }; function isObject(value) { return value && value.constructor === Object; } function copy(value) { if (isObject(value)) { var res = {}; for (var key in value) { if (hasOwnProperty.call(value, key)) { res[key] = value[key]; } } return res; } else { return value; } } function extend(dest, src) { for (var key in src) { if (hasOwnProperty.call(src, key)) { if (isObject(dest[key])) { extend(dest[key], copy(src[key])); } else { dest[key] = copy(src[key]); } } } } function mix(dest, src, shape) { for (var key in shape) { if (hasOwnProperty.call(shape, key) === false) { continue; } if (shape[key] === true) { if (key in src) { if (hasOwnProperty.call(src, key)) { dest[key] = copy(src[key]); } } } else if (shape[key]) { if (isObject(shape[key])) { var res = {}; extend(res, dest[key]); extend(res, src[key]); dest[key] = res; } else if (Array.isArray(shape[key])) { var res = {}; var innerShape = shape[key].reduce(function(s, k) { s[k] = true; return s; }, {}); for (var name in dest[key]) { if (hasOwnProperty.call(dest[key], name)) { res[name] = {}; if (dest[key] && dest[key][name]) { mix(res[name], dest[key][name], innerShape); } } } for (var name in src[key]) { if (hasOwnProperty.call(src[key], name)) { if (!res[name]) { res[name] = {}; } if (src[key] && src[key][name]) { mix(res[name], src[key][name], innerShape); } } } dest[key] = res; } } } return dest; } module.exports = function(dest, src) { return mix(dest, src, shape); };