@coco-vexel/coco-office-oojson 0.0.0-stage → 1.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,302 @@
1
+ // Tool 3: ONLYOFFICE style definitions -> OOXML styles.xml.
2
+ // Stable source: Api.GetDocument().ToJSON(false, true, true, true, true, true).
3
+ // The sixth argument exports the native styles map keyed by ONLYOFFICE numeric styleId.
4
+ import { esc, attrStr } from "./xml.mjs";
5
+ import { colorToOoxml, autoRgbAttr, highlightToOoxml } from "./color.mjs";
6
+ import { extraAttr } from "./extra.mjs";
7
+
8
+ function shdXml(shd) {
9
+ if (!shd) return "";
10
+ const fill = shd.fill ? ` w:fill="${colorToOoxml(shd.fill)}"${autoRgbAttr("oo:frgb", shd.fill)}` : "";
11
+ return `<w:shd w:val="${shd.val || "clear"}" w:color="${colorToOoxml(shd.color)}"${autoRgbAttr("oo:crgb", shd.color)}${fill}${extraAttr(shd, ["val", "color", "fill"])}/>`;
12
+ }
13
+
14
+ function bdrElXml(tag, b) {
15
+ if (!b) return "";
16
+ const a = {};
17
+ const v = b.val != null ? b.val : b.value;
18
+ if (v != null) a["w:val"] = v;
19
+ if (b.sz != null) a["w:sz"] = b.sz;
20
+ if (b.space != null) a["w:space"] = b.space;
21
+ if (b.color) a["w:color"] = colorToOoxml(b.color);
22
+ return `<w:${tag}${attrStr(a)}${b.color ? autoRgbAttr("oo:rgb", b.color) : ""}${extraAttr(b, ["color", "sz", "space", "value", "val"])}/>`;
23
+ }
24
+
25
+ const BDR_SIDES = ["top", "left", "bottom", "right", "insideH", "insideV", "start", "end", "between", "bar", "tl2br", "tr2bl"];
26
+ function bordersXml(tag, o) {
27
+ if (!o) return "";
28
+ let x = "";
29
+ for (const side of BDR_SIDES) if (o[side]) x += bdrElXml(side, o[side]);
30
+ return Object.keys(o).length ? `<w:${tag}>${x}</w:${tag}>` : `<w:${tag}/>`;
31
+ }
32
+
33
+ function widthXml(tag, w) {
34
+ if (!w) return "";
35
+ const a = {};
36
+ if (w.type != null) a["w:type"] = w.type;
37
+ const v = w.w != null ? w.w : w.value;
38
+ if (v != null) a["w:w"] = v;
39
+ return `<w:${tag}${attrStr(a)}${extraAttr(w, ["type", "w", "value"])}/>`;
40
+ }
41
+
42
+ function marXml(tag, m) {
43
+ if (!m) return "";
44
+ let x = "";
45
+ for (const side of ["top", "left", "bottom", "right", "start", "end"]) if (m[side]) x += widthXml(side, m[side]);
46
+ return x ? `<w:${tag}>${x}</w:${tag}>` : "";
47
+ }
48
+
49
+ function valOf(v) {
50
+ return typeof v === "object" && v !== null ? v.val ?? v.value ?? v.type : v;
51
+ }
52
+
53
+ export function ooOutlineToOoxml(lvl) {
54
+ if (lvl == null) return null;
55
+ const n = Number(lvl);
56
+ if (!Number.isFinite(n)) return null;
57
+ const z = n - 1;
58
+ if (z < 0) return 0;
59
+ if (z > 9) return 9;
60
+ return z;
61
+ }
62
+
63
+ function numPrXml(numPr) {
64
+ if (!numPr) return "";
65
+ let x = "";
66
+ const ilvl = valOf(numPr.ilvl);
67
+ const numId = valOf(numPr.numId);
68
+ if (ilvl != null) x += `<w:ilvl w:val="${esc(String(ilvl))}"/>`;
69
+ if (numId != null) x += `<w:numId w:val="${esc(String(numId))}"/>`;
70
+ return x || extraAttr(numPr, ["ilvl", "numId"]) ? `<w:numPr${extraAttr(numPr, ["ilvl", "numId"])}>${x}</w:numPr>` : "";
71
+ }
72
+
73
+ function tabsXml(tabs) {
74
+ if (!tabs) return "";
75
+ const list = Array.isArray(tabs) ? tabs : Array.isArray(tabs.tabs) ? tabs.tabs : Array.isArray(tabs.list) ? tabs.list : [];
76
+ let x = "";
77
+ for (const tab of list) {
78
+ if (!tab) continue;
79
+ const a = {};
80
+ const val = tab.val ?? tab.value ?? tab.type;
81
+ if (val != null) a["w:val"] = val;
82
+ if (tab.pos != null) a["w:pos"] = tab.pos;
83
+ if (tab.leader != null) a["w:leader"] = tab.leader;
84
+ x += `<w:tab${attrStr(a)}${extraAttr(tab, ["val", "value", "type", "pos", "leader"])}/>`;
85
+ }
86
+ return x ? `<w:tabs>${x}</w:tabs>` : "";
87
+ }
88
+
89
+ function ppInnerXml(pPr, options = {}) {
90
+ if (!pPr) return "";
91
+ let x = "";
92
+ if (options.includeStyleRef && pPr.pStyle != null) x += `<w:pStyle w:val="${esc(String(pPr.pStyle))}"/>`;
93
+ for (const t of ["keepNext", "keepLines", "pageBreakBefore", "widowControl", "contextualSpacing", "suppressLineNumbers"])
94
+ if (pPr[t] === true) x += `<w:${t}/>`;
95
+ x += numPrXml(pPr.numPr);
96
+ x += tabsXml(pPr.tabs);
97
+ x += bordersXml("pBdr", pPr.pBdr);
98
+ x += shdXml(pPr.shd);
99
+ if (pPr.spacing) {
100
+ const s = pPr.spacing, a = {};
101
+ if (s.before != null) a["w:before"] = s.before;
102
+ if (s.after != null) a["w:after"] = s.after;
103
+ if (s.line != null) a["w:line"] = s.line;
104
+ if (s.lineRule != null) a["w:lineRule"] = s.lineRule;
105
+ if (s.beforeAutoSpacing != null) a["w:beforeAutospacing"] = s.beforeAutoSpacing === "off" ? 0 : 1;
106
+ if (s.afterAutoSpacing != null) a["w:afterAutospacing"] = s.afterAutoSpacing === "off" ? 0 : 1;
107
+ x += `<w:spacing${attrStr(a)}${extraAttr(s, ["before", "after", "line", "lineRule", "beforeAutoSpacing", "afterAutoSpacing"])}/>`;
108
+ }
109
+ if (pPr.ind) {
110
+ const d = pPr.ind, a = {};
111
+ for (const k of ["left", "right", "firstLine", "hanging", "start", "end", "firstLineChars", "hangingChars"])
112
+ if (d[k] != null) a["w:" + k] = d[k];
113
+ x += `<w:ind${attrStr(a)}${extraAttr(d, Object.keys(a).map((k) => k.slice(2)))}/>`;
114
+ }
115
+ if (pPr.jc != null) x += `<w:jc w:val="${esc(String(pPr.jc))}"/>`;
116
+ if (pPr.textAlignment != null) x += `<w:textAlignment w:val="${esc(String(valOf(pPr.textAlignment)))}"/>`;
117
+ if (pPr.bidi === true) x += `<w:bidi/>`;
118
+ const olv = ooOutlineToOoxml(pPr.outlineLvl);
119
+ if (olv != null) x += `<w:outlineLvl w:val="${olv}"/>`;
120
+ return x;
121
+ }
122
+
123
+ export function stylePpToXml(pPr) {
124
+ const inner = ppInnerXml(pPr);
125
+ const ex = pPr ? extraAttr(pPr, ["pStyle", "keepNext", "keepLines", "pageBreakBefore", "widowControl", "contextualSpacing", "suppressLineNumbers", "numPr", "tabs", "pBdr", "shd", "spacing", "ind", "jc", "textAlignment", "bidi", "outlineLvl", "type", "bFromDocument"]) : "";
126
+ return inner || ex ? `<w:pPr${ex}>${inner}</w:pPr>` : "";
127
+ }
128
+
129
+ function underlineXml(u) {
130
+ if (u == null) return "";
131
+ if (u === false) return `<w:u w:val="none"/>`;
132
+ if (u === true) return `<w:u w:val="single"/>`;
133
+ if (typeof u !== "object") return `<w:u w:val="${esc(String(u))}"/>`;
134
+ const a = {};
135
+ const val = u.val ?? u.value ?? u.type;
136
+ if (val != null) a["w:val"] = val;
137
+ if (u.color) a["w:color"] = colorToOoxml(u.color);
138
+ return `<w:u${attrStr(a)}${u.color ? autoRgbAttr("oo:rgb", u.color) : ""}${extraAttr(u, ["val", "value", "type", "color"])}/>`;
139
+ }
140
+
141
+ function rpInnerXml(rPr) {
142
+ if (!rPr) return "";
143
+ let x = "";
144
+ if (rPr.rFonts) {
145
+ const f = rPr.rFonts, a = {};
146
+ for (const k of ["ascii", "hAnsi", "eastAsia", "cs", "hint", "asciiTheme", "hAnsiTheme", "eastAsiaTheme", "cstheme", "csTheme"])
147
+ if (f[k] != null) a["w:" + k] = f[k];
148
+ x += `<w:rFonts${attrStr(a)}${extraAttr(f, Object.keys(a).map((k) => k.slice(2)))}/>`;
149
+ }
150
+ const tgl = (name, v) => (v === true ? `<w:${name}/>` : v === false ? `<w:${name} w:val="false"/>` : "");
151
+ for (const name of ["b", "bCs", "i", "iCs", "strike", "dstrike", "caps", "smallCaps", "vanish", "rtl", "noProof"])
152
+ x += tgl(name, rPr[name]);
153
+ x += underlineXml(rPr.u);
154
+ if (rPr.color) x += `<w:color w:val="${colorToOoxml(rPr.color)}"${autoRgbAttr("oo:rgb", rPr.color)}/>`;
155
+ if (rPr.spacing != null) x += `<w:spacing w:val="${rPr.spacing}"/>`;
156
+ if (rPr.position != null) x += `<w:position w:val="${rPr.position}"/>`;
157
+ if (rPr.kern != null) x += `<w:kern w:val="${rPr.kern}"/>`;
158
+ if (rPr.sz != null) x += `<w:sz w:val="${rPr.sz}"/>`;
159
+ if (rPr.szCs != null) x += `<w:szCs w:val="${rPr.szCs}"/>`;
160
+ if (rPr.highlight) {
161
+ const h = highlightToOoxml(rPr.highlight);
162
+ if (h) x += `<w:highlight w:val="${h}"/>`;
163
+ }
164
+ if (rPr.vertAlign != null) x += `<w:vertAlign w:val="${esc(String(valOf(rPr.vertAlign)))}"/>`;
165
+ x += shdXml(rPr.shd);
166
+ if (rPr.lang) {
167
+ const a = {};
168
+ for (const k of ["val", "eastAsia", "bidi"]) if (rPr.lang[k] != null) a["w:" + k] = rPr.lang[k];
169
+ x += `<w:lang${attrStr(a)}${extraAttr(rPr.lang, ["val", "eastAsia", "bidi"])}/>`;
170
+ }
171
+ return x;
172
+ }
173
+
174
+ export function styleRpToXml(rPr) {
175
+ const inner = rpInnerXml(rPr);
176
+ const ex = rPr ? extraAttr(rPr, ["rFonts", "b", "bCs", "i", "iCs", "strike", "dstrike", "caps", "smallCaps", "vanish", "rtl", "noProof", "u", "color", "spacing", "position", "kern", "sz", "szCs", "highlight", "vertAlign", "shd", "lang", "type", "bFromDocument"]) : "";
177
+ return inner || ex ? `<w:rPr${ex}>${inner}</w:rPr>` : "";
178
+ }
179
+
180
+ function tblPrXml(t) {
181
+ if (!t) return "";
182
+ let x = "";
183
+ if (t.tblStyle != null) x += `<w:tblStyle w:val="${esc(String(t.tblStyle))}"/>`;
184
+ x += widthXml("tblW", t.tblW);
185
+ if (t.jc != null) x += `<w:jc w:val="${esc(String(t.jc))}"/>`;
186
+ x += bordersXml("tblBorders", t.tblBorders);
187
+ x += shdXml(t.shd);
188
+ x += marXml("tblCellMar", t.tblCellMar);
189
+ if (t.tblLayout != null) x += `<w:tblLayout w:type="${esc(String(valOf(t.tblLayout)))}"/>`;
190
+ if (t.tblLook != null && typeof t.tblLook === "object") {
191
+ const a = {};
192
+ for (const k of Object.keys(t.tblLook)) if (k !== "type") a["w:" + k] = t.tblLook[k] === true ? 1 : t.tblLook[k] === false ? 0 : t.tblLook[k];
193
+ x += `<w:tblLook${attrStr(a)}/>`;
194
+ }
195
+ const ex = extraAttr(t, ["tblStyle", "tblW", "jc", "tblBorders", "shd", "tblCellMar", "tblLayout", "tblLook", "type"]);
196
+ return x || ex ? `<w:tblPr${ex}>${x}</w:tblPr>` : "";
197
+ }
198
+
199
+ function trPrXml(p) {
200
+ if (!p) return "";
201
+ let x = "";
202
+ if (p.tblHeader === true) x += `<w:tblHeader/>`;
203
+ if (p.cantSplit === true) x += `<w:cantSplit/>`;
204
+ if (p.jc != null) x += `<w:jc w:val="${esc(String(p.jc))}"/>`;
205
+ if (p.trHeight) x += `<w:trHeight${attrStr({ "w:val": p.trHeight.value != null ? p.trHeight.value : p.trHeight.val, "w:hRule": p.trHeight.hRule })}${extraAttr(p.trHeight, ["value", "val", "hRule"])}/>`;
206
+ const ex = extraAttr(p, ["tblHeader", "cantSplit", "jc", "trHeight", "type"]);
207
+ return x || ex ? `<w:trPr${ex}>${x}</w:trPr>` : "";
208
+ }
209
+
210
+ function tcPrXml(p) {
211
+ if (!p) return "";
212
+ let x = "";
213
+ x += widthXml("tcW", p.tcW);
214
+ if (p.gridSpan != null) x += `<w:gridSpan w:val="${p.gridSpan}"/>`;
215
+ if (p.vMerge != null) x += `<w:vMerge${p.vMerge && p.vMerge !== "continue" ? ` w:val="${esc(String(p.vMerge))}"` : ""}/>`;
216
+ x += bordersXml("tcBorders", p.tcBorders);
217
+ x += shdXml(p.shd);
218
+ x += marXml("tcMar", p.tcMar);
219
+ if (p.vAlign != null) x += `<w:vAlign w:val="${esc(String(valOf(p.vAlign)))}"/>`;
220
+ if (p.noWrap === true) x += `<w:noWrap/>`;
221
+ const ex = extraAttr(p, ["tcW", "gridSpan", "vMerge", "tcBorders", "shd", "tcMar", "vAlign", "noWrap", "type"]);
222
+ return x || ex ? `<w:tcPr${ex}>${x}</w:tcPr>` : "";
223
+ }
224
+
225
+ function styleType(t) {
226
+ switch (t) {
227
+ case "paragraphStyle": return "paragraph";
228
+ case "characterStyle": return "character";
229
+ case "tableStyle": return "table";
230
+ case "numberingStyle": return "numbering";
231
+ case "character": case "table": case "numbering": case "paragraph": return t;
232
+ default: return "paragraph";
233
+ }
234
+ }
235
+
236
+ function tableStyleType(t) {
237
+ switch (t) {
238
+ case "topLeftCell": return "nwCell";
239
+ case "topRightCell": return "neCell";
240
+ case "bottomLeftCell": return "swCell";
241
+ case "bottomRightCell": return "seCell";
242
+ default: return t;
243
+ }
244
+ }
245
+
246
+ function tableStylePrXml(type, pr) {
247
+ if (!pr) return "";
248
+ const wType = tableStyleType(pr.styleType ?? type);
249
+ if (!wType) return "";
250
+ const inner = stylePpToXml(pr.pPr) + styleRpToXml(pr.rPr) + tblPrXml(pr.tblPr) + trPrXml(pr.trPr) + tcPrXml(pr.tcPr);
251
+ const ex = extraAttr(pr, ["styleType", "pPr", "rPr", "tblPr", "trPr", "tcPr", "type"]);
252
+ return inner || ex ? `<w:tblStylePr w:type="${esc(String(wType))}"${ex}>${inner}</w:tblStylePr>` : "";
253
+ }
254
+
255
+ function tableStylePrListXml(tblStylePr) {
256
+ if (!tblStylePr || typeof tblStylePr !== "object") return "";
257
+ let x = "";
258
+ for (const key of Object.keys(tblStylePr)) x += tableStylePrXml(key, tblStylePr[key]);
259
+ return x;
260
+ }
261
+
262
+ export function styleToXml(styleId, s) {
263
+ if (!s || styleId == null) return "";
264
+ const type = styleType(s.styleType ?? s.type);
265
+ const attrs = { "w:type": type, "w:styleId": String(styleId) };
266
+ if (s.default === true) attrs["w:default"] = "1";
267
+ if (s.customStyle === true) attrs["w:customStyle"] = "1";
268
+ let inner = "";
269
+ if (s.name != null) inner += `<w:name w:val="${esc(String(s.name))}"/>`;
270
+ if (s.basedOn != null && s.basedOn !== "") inner += `<w:basedOn w:val="${esc(String(s.basedOn))}"/>`;
271
+ if (s.next != null && s.next !== "") inner += `<w:next w:val="${esc(String(s.next))}"/>`;
272
+ if (s.link != null && s.link !== "") inner += `<w:link w:val="${esc(String(s.link))}"/>`;
273
+ if (s.hidden === true) inner += `<w:hidden/>`;
274
+ if (s.uiPriority != null) inner += `<w:uiPriority w:val="${s.uiPriority}"/>`;
275
+ if (s.semiHidden === true) inner += `<w:semiHidden/>`;
276
+ if (s.unhideWhenUsed === true) inner += `<w:unhideWhenUsed/>`;
277
+ if (s.qFormat === true) inner += `<w:qFormat/>`;
278
+ inner += stylePpToXml(s.pPr);
279
+ inner += styleRpToXml(s.rPr);
280
+ inner += tblPrXml(s.tblPr);
281
+ inner += trPrXml(s.trPr);
282
+ inner += tcPrXml(s.tcPr);
283
+ inner += tableStylePrListXml(s.tblStylePr);
284
+ return `<w:style${attrStr(attrs)}>${inner}</w:style>`;
285
+ }
286
+
287
+ export function buildStylesXml(styles, docDefaults) {
288
+ let dd = "";
289
+ if (docDefaults && (docDefaults.paraPr || docDefaults.textPr)) {
290
+ const rpr = styleRpToXml(docDefaults.textPr);
291
+ const ppr = stylePpToXml(docDefaults.paraPr);
292
+ dd = `<w:docDefaults><w:rPrDefault>${rpr}</w:rPrDefault><w:pPrDefault>${ppr}</w:pPrDefault></w:docDefaults>`;
293
+ }
294
+ const body = (styles || []).map((it) => styleToXml(it.styleId, it.def)).join("");
295
+ return (
296
+ `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
297
+ `<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:oo="urn:coco:oojson">` +
298
+ dd +
299
+ body +
300
+ `</w:styles>`
301
+ );
302
+ }