PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Shared / lib / owned-globals.js

owned-globals.js in Extendify 3.2.1, at src/Shared/lib/owned-globals.js

82 lines 2.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { isObject } from '@shared/lib/utils';
2
3 const leafPaths = (value, prefix) => {
4 // An empty object, or PHP's [] for one, would purge the whole branch.
5 if (Array.isArray(value) && value.length === 0) return [];
6 if (!isObject(value)) return [prefix];
7
8 const entries = Object.entries(value);
9 if (entries.length === 0) return [];
10
11 return entries.flatMap(([key, child]) => leafPaths(child, [...prefix, key]));
12 };
13
14 export const collectOwnedPaths = ({ payloads, section, roots, exclude }) => {
15 const paths = new Map();
16
17 for (const payload of Object.values(payloads ?? {})) {
18 const source = payload?.[section];
19 if (!isObject(source)) continue;
20
21 for (const key of roots) {
22 if (!(key in source)) continue;
23
24 for (const path of leafPaths(source[key], [key])) {
25 if (exclude?.(section, path)) continue;
26 paths.set(path.join('.'), path);
27 }
28 }
29 }
30
31 return [...paths.values()];
32 };
33
34 const valueAtPath = (source, path) =>
35 path.reduce(
36 (value, key) => (isObject(value) ? value[key] : undefined),
37 source,
38 );
39
40 const withoutPath = (source, [key, ...rest]) => {
41 if (!isObject(source) || !(key in source)) return source;
42
43 const updated = { ...source };
44
45 if (rest.length === 0) {
46 delete updated[key];
47 return updated;
48 }
49
50 const child = withoutPath(updated[key], rest);
51
52 if (isObject(child) && Object.keys(child).length === 0) {
53 delete updated[key];
54 } else {
55 updated[key] = child;
56 }
57
58 return updated;
59 };
60
61 const withPath = (source, [key, ...rest], value) => {
62 const updated = isObject(source) ? { ...source } : {};
63 updated[key] =
64 rest.length === 0 ? value : withPath(updated[key], rest, value);
65 return updated;
66 };
67
68 export const purgeOwnedPaths = (section, ownedPaths) =>
69 ownedPaths.reduce((current, path) => withoutPath(current, path), section);
70
71 // Purging first is what stops the outgoing payload's leaves surviving a switch.
72 export const applyOwnedSection = (current, incoming, ownedPaths) => {
73 const purged = purgeOwnedPaths(current, ownedPaths);
74
75 if (!isObject(incoming)) return purged;
76
77 return ownedPaths.reduce((section, path) => {
78 const value = valueAtPath(incoming, path);
79 return value === undefined ? section : withPath(section, path, value);
80 }, purged);
81 };
82