summaryrefslogtreecommitdiff
path: root/packages/frontend/src/scripts/merge.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/scripts/merge.ts')
-rw-r--r--packages/frontend/src/scripts/merge.ts31
1 files changed, 31 insertions, 0 deletions
diff --git a/packages/frontend/src/scripts/merge.ts b/packages/frontend/src/scripts/merge.ts
new file mode 100644
index 0000000000..60097051fa
--- /dev/null
+++ b/packages/frontend/src/scripts/merge.ts
@@ -0,0 +1,31 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { deepClone } from './clone.js';
+import type { Cloneable } from './clone.js';
+
+function isPureObject(value: unknown): value is Record<string | number | symbol, unknown> {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
+/**
+ * valueにないキーをdefからもらう(再帰的)\
+ * nullはそのまま、undefinedはdefの値
+ **/
+export function deepMerge<X extends Record<string | number | symbol, unknown>>(value: X, def: X): X {
+ if (isPureObject(value) && isPureObject(def)) {
+ const result = deepClone(value as Cloneable) as X;
+ for (const [k, v] of Object.entries(def) as [keyof X, X[keyof X]][]) {
+ if (!Object.prototype.hasOwnProperty.call(value, k) || value[k] === undefined) {
+ result[k] = v;
+ } else if (isPureObject(v) && isPureObject(result[k])) {
+ const child = deepClone(result[k] as Cloneable) as X[keyof X] & Record<string | number | symbol, unknown>;
+ result[k] = deepMerge<typeof v>(child, v);
+ }
+ }
+ return result;
+ }
+ return value;
+}