@jxsuite/studio 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Site context helpers - merge site-level definitions with file-level.
3
+ *
4
+ * When a project has a project.json, its $media and style cascade into every file. File-level
5
+ * definitions merge on top (file wins on conflict).
6
+ */
7
+
8
+ import { projectState, setProjectState } from "./store.js";
9
+ import { getPlatform } from "./platform.js";
10
+
11
+ /**
12
+ * Merge site $media with document $media. Document keys win on conflict.
13
+ *
14
+ * @param {any} docMedia - The current document's $media (may be undefined)
15
+ * @returns {any}
16
+ */
17
+ export function getEffectiveMedia(docMedia) {
18
+ const siteMedia = projectState?.projectConfig?.$media;
19
+ if (!siteMedia) return docMedia || {};
20
+ if (!docMedia) return { ...siteMedia };
21
+ return { ...siteMedia, ...docMedia };
22
+ }
23
+
24
+ /**
25
+ * Merge site style with document style. Document keys win on conflict. Nested selector objects
26
+ * (e.g. `& li`) are shallow-merged individually.
27
+ *
28
+ * @param {any} docStyle - The current document's style (may be undefined)
29
+ * @returns {any}
30
+ */
31
+ export function getEffectiveStyle(docStyle) {
32
+ const siteStyle = projectState?.projectConfig?.style;
33
+ if (!siteStyle) return docStyle || {};
34
+ if (!docStyle) return { ...siteStyle };
35
+ const merged = { ...siteStyle };
36
+ for (const [k, v] of Object.entries(docStyle)) {
37
+ if (
38
+ typeof v === "object" &&
39
+ v !== null &&
40
+ typeof merged[k] === "object" &&
41
+ merged[k] !== null
42
+ ) {
43
+ merged[k] = { ...merged[k], ...v };
44
+ } else {
45
+ merged[k] = v;
46
+ }
47
+ }
48
+ return merged;
49
+ }
50
+
51
+ /**
52
+ * Merge site imports with document imports. Document keys win on conflict.
53
+ *
54
+ * @param {any} docImports - The current document's imports (may be undefined)
55
+ * @returns {any}
56
+ */
57
+ export function getEffectiveImports(docImports) {
58
+ const siteImports = projectState?.projectConfig?.imports;
59
+ if (!siteImports) return docImports || {};
60
+ if (!docImports) return { ...siteImports };
61
+ return { ...siteImports, ...docImports };
62
+ }
63
+
64
+ /**
65
+ * Merge site $elements with document $elements. Union with dedup by $ref or string value.
66
+ *
67
+ * @param {any[]} [docElements] - The current document's $elements (may be undefined)
68
+ * @returns {any[]}
69
+ */
70
+ export function getEffectiveElements(docElements) {
71
+ const siteElements = projectState?.projectConfig?.$elements;
72
+ if (!siteElements?.length) return docElements || [];
73
+ if (!docElements?.length) return [...siteElements];
74
+ /** @type {Set<string>} */
75
+ const seen = new Set();
76
+ /** @type {any[]} */
77
+ const merged = [];
78
+ for (const entry of [...siteElements, ...docElements]) {
79
+ const key = typeof entry === "string" ? entry : entry?.$ref;
80
+ if (key && !seen.has(key)) {
81
+ seen.add(key);
82
+ merged.push(entry);
83
+ }
84
+ }
85
+ return merged;
86
+ }
87
+
88
+ /**
89
+ * Merge site $head with document $head. Union with dedup by href/src.
90
+ *
91
+ * @param {any[]} [docHead] - The current document's $head (may be undefined)
92
+ * @returns {any[]}
93
+ */
94
+ export function getEffectiveHead(docHead) {
95
+ const siteHead = projectState?.projectConfig?.$head;
96
+ if (!siteHead?.length) return docHead || [];
97
+ if (!docHead?.length) return [...siteHead];
98
+ /** @type {Set<string>} */
99
+ const seen = new Set();
100
+ /** @type {any[]} */
101
+ const merged = [];
102
+ for (const entry of [...siteHead, ...docHead]) {
103
+ const key = entry?.attributes?.href || entry?.attributes?.src || JSON.stringify(entry);
104
+ if (!seen.has(key)) {
105
+ seen.add(key);
106
+ merged.push(entry);
107
+ }
108
+ }
109
+ return merged;
110
+ }
111
+
112
+ /**
113
+ * Update the project's project.json with a partial patch and persist to disk.
114
+ *
115
+ * @param {Record<string, any>} patch - Fields to merge into the current projectConfig
116
+ */
117
+ export async function updateSiteConfig(patch) {
118
+ const platform = getPlatform();
119
+ const config = { ...projectState.projectConfig, ...patch };
120
+ await platform.writeFile("project.json", JSON.stringify(config, null, 2));
121
+ setProjectState({ ...projectState, projectConfig: config });
122
+ }