From 3374efe7624463f7a1c5375d2cff57ee072f683e Mon Sep 17 00:00:00 2001
From: ezsh <ezsh.junk@gmail.com>
Date: Tue, 28 May 2019 02:26:37 +0200
Subject: [PATCH] Make mergeRules work with hierarchical objects

---
 src/js/rulesAssistant.js | 58 +++++++++++++++++++++++++++++-----------
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index 648662d4f70..047aa8bde13 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -58,23 +58,51 @@ window.lastPregRule = function(slave, rules) {
 };
 
 /**
- * @param {App.RA.Rule[]} rules
+ * @param {App.RA.RuleSetters[]} rules
  * @returns {App.RA.RuleSetters}
  */
-window.mergeRules = function (rules) {
-	const combinedRule = {};
-	rules.forEach(rule => {
-		// A rule overrides any preceding ones if,
-		// * there are no preceding ones,
-		// * or it sets autoBrand,
-		// * or it does not set autoBrand and is not null
-		Object.keys(rule).forEach(key => {
-			const applies = (combinedRule[key] === undefined ||
-				(key === "autoBrand" && rule[key]) ||
-				(key !== "autoBrand" && rule[key] !== null));
-			if (!applies) return;
-			combinedRule[key] = rule[key];
-		});
+window.mergeRules = function(rules) {
+	if (rules.length === 0) {
+		return emptyDefaultRule().set;
+	} else if (rules.length === 1) {
+		return rules[0];
+	}
+
+	function isObject(o) {
+		return (o !== undefined && o !== null && typeof o === 'object' && !Array.isArray(o));
+	}
+
+	function deepAssign(target, source) {
+		for (const key in source) {
+			if (!source.hasOwnProperty(key)) {
+				continue;
+			}
+			if (isObject(source[key])) {
+				if (!target.hasOwnProperty(key) || target[key] === null) {
+					target[key] = {};
+				}
+				deepAssign(target[key], source[key]);
+			} else {
+				// A rule overrides any preceding ones if,
+				// * there are no preceding ones,
+				// * or it sets autoBrand,
+				// * or it does not set autoBrand and is not null
+				const overrides = (
+					target[key] === undefined || target[key] === null ||
+					(key === "autoBrand" && source[key]) ||
+					(key !== "autoBrand" && source[key] !== null));
+				if (overrides) {
+					target[key] = source[key];
+				}
+			}
+		}
+	}
+
+	const combinedRule = rules[0];
+	const otherRules = rules.slice(1);
+
+	otherRules.forEach(rule => {
+		deepAssign(combinedRule, rule);
 	});
 	return combinedRule;
 };
-- 
GitLab