@arbidocs/coedit 0.0.0-stage → 0.4.33
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.
- package/LICENSE +21 -0
- package/dist/encoding.cjs +715 -0
- package/dist/encoding.cjs.map +1 -0
- package/dist/encoding.d.cts +192 -0
- package/dist/encoding.d.ts +192 -0
- package/dist/encoding.js +680 -0
- package/dist/encoding.js.map +1 -0
- package/dist/hocuspocus.cjs +1723 -0
- package/dist/hocuspocus.cjs.map +1 -0
- package/dist/hocuspocus.d.cts +39 -0
- package/dist/hocuspocus.d.ts +39 -0
- package/dist/hocuspocus.js +1700 -0
- package/dist/hocuspocus.js.map +1 -0
- package/dist/index.cjs +1656 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1628 -0
- package/dist/index.js.map +1 -0
- package/dist/server.cjs +1816 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +43 -0
- package/dist/server.d.ts +43 -0
- package/dist/server.js +1786 -0
- package/dist/server.js.map +1 -0
- package/dist/session-Cf9iu1Vt.d.cts +82 -0
- package/dist/session-Cf9iu1Vt.d.ts +82 -0
- package/dist/versions-DXiFQMA6.d.cts +8 -0
- package/dist/versions-DXiFQMA6.d.ts +8 -0
- package/package.json +60 -4
- package/README.md +0 -3
package/dist/encoding.js
ADDED
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
import * as Y from 'yjs';
|
|
2
|
+
import { readOoxmlPart, validateExternalTarget, relsPartNameFor, writeOoxmlPackage, readOoxmlPackage } from '@docx-editor.dev/core/store';
|
|
3
|
+
|
|
4
|
+
// src/encoding.ts
|
|
5
|
+
|
|
6
|
+
// src/rich.ts
|
|
7
|
+
var WML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
8
|
+
var WRAPPERS = /* @__PURE__ */ new Set([
|
|
9
|
+
"ins",
|
|
10
|
+
"del",
|
|
11
|
+
"moveFrom",
|
|
12
|
+
"moveTo",
|
|
13
|
+
"hyperlink",
|
|
14
|
+
"smartTag",
|
|
15
|
+
"fldSimple",
|
|
16
|
+
"customXml",
|
|
17
|
+
"dir",
|
|
18
|
+
"bdo",
|
|
19
|
+
"sdtContent"
|
|
20
|
+
]);
|
|
21
|
+
var TEXT_ELEMENTS = /* @__PURE__ */ new Set(["t", "delText", "instrText"]);
|
|
22
|
+
var isEl = (n) => typeof n !== "string";
|
|
23
|
+
var isWml = (el, local) => el.ns === WML && el.local === local;
|
|
24
|
+
function describe(el) {
|
|
25
|
+
const desc = { ns: el.ns, local: el.local, attrs: el.attrs, bindings: el.bindings };
|
|
26
|
+
if (el.prefix !== void 0) desc.prefix = el.prefix;
|
|
27
|
+
return desc;
|
|
28
|
+
}
|
|
29
|
+
function withChildren(desc, children, id) {
|
|
30
|
+
const el = {
|
|
31
|
+
ns: desc.ns,
|
|
32
|
+
local: desc.local,
|
|
33
|
+
attrs: desc.attrs,
|
|
34
|
+
bindings: desc.bindings,
|
|
35
|
+
children
|
|
36
|
+
};
|
|
37
|
+
if (desc.prefix !== void 0) el.prefix = desc.prefix;
|
|
38
|
+
if (id !== void 0) el._id = id;
|
|
39
|
+
return el;
|
|
40
|
+
}
|
|
41
|
+
var counter = 0;
|
|
42
|
+
function newRunId() {
|
|
43
|
+
counter += 1;
|
|
44
|
+
return `${Math.random().toString(36).slice(2, 8)}${counter.toString(36)}`;
|
|
45
|
+
}
|
|
46
|
+
var Unrepresentable = class extends Error {
|
|
47
|
+
};
|
|
48
|
+
function fail() {
|
|
49
|
+
throw new Unrepresentable();
|
|
50
|
+
}
|
|
51
|
+
function encodeRun(run, wrappers, out) {
|
|
52
|
+
const children = run.children;
|
|
53
|
+
let rPr = null;
|
|
54
|
+
let start = 0;
|
|
55
|
+
const first = children[0];
|
|
56
|
+
if (first !== void 0 && isEl(first) && isWml(first, "rPr")) {
|
|
57
|
+
rPr = first;
|
|
58
|
+
start = 1;
|
|
59
|
+
}
|
|
60
|
+
const base = { r: rPr, ra: describe(run), ri: run._id ?? newRunId(), w: wrappers };
|
|
61
|
+
let produced = false;
|
|
62
|
+
for (let i = start; i < children.length; i++) {
|
|
63
|
+
const child = children[i];
|
|
64
|
+
if (!isEl(child)) fail();
|
|
65
|
+
const only = child.children[0];
|
|
66
|
+
if (child.ns === WML && TEXT_ELEMENTS.has(child.local) && child.children.length === 1 && typeof only === "string" && only.length > 0) {
|
|
67
|
+
const tx = describe(child);
|
|
68
|
+
for (let c = 0; c < only.length; c++) out.push({ v: only[c], a: { ...base, tx, k: null } });
|
|
69
|
+
} else {
|
|
70
|
+
out.push({ v: { x: child }, a: { ...base, tx: null, k: null } });
|
|
71
|
+
}
|
|
72
|
+
produced = true;
|
|
73
|
+
}
|
|
74
|
+
if (!produced)
|
|
75
|
+
out.push({
|
|
76
|
+
v: { x: { ns: WML, local: "e", attrs: [], bindings: [], children: [] } },
|
|
77
|
+
a: { ...base, tx: null, k: "e" }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function encodeInline(children, wrappers, out) {
|
|
81
|
+
for (const child of children) {
|
|
82
|
+
if (!isEl(child)) fail();
|
|
83
|
+
if (child.ns === WML && child.local === "r") {
|
|
84
|
+
encodeRun(child, wrappers, out);
|
|
85
|
+
} else if (child.ns === WML && WRAPPERS.has(child.local)) {
|
|
86
|
+
const before = out.length;
|
|
87
|
+
const desc = { ...describe(child), head: [], id: child._id ?? newRunId() };
|
|
88
|
+
let ok = true;
|
|
89
|
+
const inner = [];
|
|
90
|
+
try {
|
|
91
|
+
encodeInline(child.children, [...wrappers, desc], inner);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (!(error instanceof Unrepresentable)) throw error;
|
|
94
|
+
ok = false;
|
|
95
|
+
}
|
|
96
|
+
if (ok && inner.length > 0) out.push(...inner);
|
|
97
|
+
else {
|
|
98
|
+
out.length = before;
|
|
99
|
+
out.push(atom(child, wrappers));
|
|
100
|
+
}
|
|
101
|
+
} else if (child.ns === WML && child.local === "sdt") {
|
|
102
|
+
const last = child.children[child.children.length - 1];
|
|
103
|
+
const head = child.children.slice(0, -1);
|
|
104
|
+
if (last !== void 0 && isEl(last) && isWml(last, "sdtContent") && head.every(isEl)) {
|
|
105
|
+
const before = out.length;
|
|
106
|
+
const sdt = {
|
|
107
|
+
...describe(child),
|
|
108
|
+
head,
|
|
109
|
+
id: child._id ?? newRunId()
|
|
110
|
+
};
|
|
111
|
+
const content = { ...describe(last), head: [], id: last._id ?? newRunId() };
|
|
112
|
+
const inner = [];
|
|
113
|
+
let ok = true;
|
|
114
|
+
try {
|
|
115
|
+
encodeInline(last.children, [...wrappers, sdt, content], inner);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!(error instanceof Unrepresentable)) throw error;
|
|
118
|
+
ok = false;
|
|
119
|
+
}
|
|
120
|
+
if (ok && inner.length > 0) out.push(...inner);
|
|
121
|
+
else {
|
|
122
|
+
out.length = before;
|
|
123
|
+
out.push(atom(child, wrappers));
|
|
124
|
+
}
|
|
125
|
+
} else out.push(atom(child, wrappers));
|
|
126
|
+
} else {
|
|
127
|
+
out.push(atom(child, wrappers));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function atom(el, wrappers) {
|
|
132
|
+
return { v: { x: el }, a: { r: null, ra: null, ri: null, w: wrappers, tx: null, k: "a" } };
|
|
133
|
+
}
|
|
134
|
+
function encodeParagraph(children) {
|
|
135
|
+
const head = [];
|
|
136
|
+
let start = 0;
|
|
137
|
+
const first = children[0];
|
|
138
|
+
if (first !== void 0 && isEl(first) && isWml(first, "pPr")) {
|
|
139
|
+
head.push(first);
|
|
140
|
+
start = 1;
|
|
141
|
+
}
|
|
142
|
+
const units = [];
|
|
143
|
+
try {
|
|
144
|
+
encodeInline(children.slice(start), [], units);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error instanceof Unrepresentable) return null;
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
return { head, units };
|
|
150
|
+
}
|
|
151
|
+
var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
152
|
+
function decodeRange(units, from, to, depth) {
|
|
153
|
+
const out = [];
|
|
154
|
+
let i = from;
|
|
155
|
+
while (i < to) {
|
|
156
|
+
const unit = units[i];
|
|
157
|
+
const { w } = unit.a;
|
|
158
|
+
if (w.length > depth) {
|
|
159
|
+
const wrapper = w[depth];
|
|
160
|
+
let j = i + 1;
|
|
161
|
+
while (j < to && units[j].a.w.length > depth && same(units[j].a.w[depth], wrapper)) j++;
|
|
162
|
+
out.push(
|
|
163
|
+
withChildren(wrapper, [...wrapper.head, ...decodeRange(units, i, j, depth + 1)], wrapper.id)
|
|
164
|
+
);
|
|
165
|
+
i = j;
|
|
166
|
+
} else if (unit.a.k === "a") {
|
|
167
|
+
out.push(unit.v.x);
|
|
168
|
+
i++;
|
|
169
|
+
} else {
|
|
170
|
+
let j = i + 1;
|
|
171
|
+
while (unit.a.k !== "e" && j < to && units[j].a.w.length === depth && units[j].a.k !== "a" && units[j].a.k !== "e" && units[j].a.ri === unit.a.ri && same(units[j].a.r, unit.a.r) && same(units[j].a.ra, unit.a.ra)) {
|
|
172
|
+
j++;
|
|
173
|
+
}
|
|
174
|
+
out.push(decodeRun(units, i, j));
|
|
175
|
+
i = j;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
function decodeRun(units, from, to) {
|
|
181
|
+
const { r, ra } = units[from].a;
|
|
182
|
+
const children = [];
|
|
183
|
+
if (r) children.push(r);
|
|
184
|
+
let i = from;
|
|
185
|
+
while (i < to) {
|
|
186
|
+
const unit = units[i];
|
|
187
|
+
if (unit.a.k === "e") {
|
|
188
|
+
i++;
|
|
189
|
+
} else if (typeof unit.v === "string") {
|
|
190
|
+
let j = i + 1;
|
|
191
|
+
while (j < to && typeof units[j].v === "string" && same(units[j].a.tx, unit.a.tx)) j++;
|
|
192
|
+
let text = "";
|
|
193
|
+
for (let c = i; c < j; c++) text += units[c].v;
|
|
194
|
+
children.push(withChildren(unit.a.tx, [text]));
|
|
195
|
+
i = j;
|
|
196
|
+
} else {
|
|
197
|
+
children.push(unit.v.x);
|
|
198
|
+
i++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return withChildren(ra, children, units[from].a.ri ?? void 0);
|
|
202
|
+
}
|
|
203
|
+
function decodeInline(units) {
|
|
204
|
+
return decodeRange(units, 0, units.length, 0);
|
|
205
|
+
}
|
|
206
|
+
var KEYS = ["r", "ra", "ri", "w", "tx", "k"];
|
|
207
|
+
function toAttributes(a) {
|
|
208
|
+
const out = {};
|
|
209
|
+
for (const key of KEYS) {
|
|
210
|
+
const value = a[key];
|
|
211
|
+
if (value !== null && !(key === "w" && value.length === 0)) out[key] = value;
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
function fromAttributes(attributes) {
|
|
216
|
+
const a = attributes ?? {};
|
|
217
|
+
return {
|
|
218
|
+
r: a.r ?? null,
|
|
219
|
+
ra: a.ra ?? null,
|
|
220
|
+
ri: a.ri ?? null,
|
|
221
|
+
w: a.w ?? [],
|
|
222
|
+
tx: a.tx ?? null,
|
|
223
|
+
k: a.k ?? null
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function readUnits(text) {
|
|
227
|
+
const units = [];
|
|
228
|
+
for (const op of text.toDelta()) {
|
|
229
|
+
const a = fromAttributes(op.attributes);
|
|
230
|
+
if (typeof op.insert === "string") {
|
|
231
|
+
for (let i = 0; i < op.insert.length; i++) units.push({ v: op.insert[i], a });
|
|
232
|
+
} else {
|
|
233
|
+
units.push({ v: op.insert, a });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return units;
|
|
237
|
+
}
|
|
238
|
+
var valueKeyOf = (u) => typeof u.v === "string" ? u.v : JSON.stringify(u.v);
|
|
239
|
+
var attrsKeyOf = (u) => JSON.stringify(u.a);
|
|
240
|
+
function attributeChange(from, to) {
|
|
241
|
+
const a = toAttributes(from);
|
|
242
|
+
const b = toAttributes(to);
|
|
243
|
+
const change = {};
|
|
244
|
+
for (const key of KEYS) {
|
|
245
|
+
if (JSON.stringify(a[key]) !== JSON.stringify(b[key])) change[key] = b[key] ?? null;
|
|
246
|
+
}
|
|
247
|
+
return change;
|
|
248
|
+
}
|
|
249
|
+
function pushRetain(delta, length, attributes) {
|
|
250
|
+
if (length === 0) return;
|
|
251
|
+
const last = delta[delta.length - 1];
|
|
252
|
+
const empty = !attributes || Object.keys(attributes).length === 0;
|
|
253
|
+
if (last && last.retain !== void 0 && !last.attributes && empty) {
|
|
254
|
+
last.retain += length;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
delta.push(empty ? { retain: length } : { retain: length, attributes });
|
|
258
|
+
}
|
|
259
|
+
function reformat(delta, previous, from, next, to, length) {
|
|
260
|
+
let i = 0;
|
|
261
|
+
while (i < length) {
|
|
262
|
+
const change = attributeChange(previous[from + i].a, next[to + i].a);
|
|
263
|
+
const key = JSON.stringify(change);
|
|
264
|
+
let j = i + 1;
|
|
265
|
+
while (j < length && JSON.stringify(attributeChange(previous[from + j].a, next[to + j].a)) === key) {
|
|
266
|
+
j++;
|
|
267
|
+
}
|
|
268
|
+
pushRetain(delta, j - i, change);
|
|
269
|
+
i = j;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function applyUnits(text, previous, next) {
|
|
273
|
+
let start = 0;
|
|
274
|
+
const limit = Math.min(previous.length, next.length);
|
|
275
|
+
while (start < limit && valueKeyOf(previous[start]) === valueKeyOf(next[start])) start++;
|
|
276
|
+
let endPrev = previous.length;
|
|
277
|
+
let endNext = next.length;
|
|
278
|
+
while (endPrev > start && endNext > start && valueKeyOf(previous[endPrev - 1]) === valueKeyOf(next[endNext - 1])) {
|
|
279
|
+
endPrev--;
|
|
280
|
+
endNext--;
|
|
281
|
+
}
|
|
282
|
+
const delta = [];
|
|
283
|
+
reformat(delta, previous, 0, next, 0, start);
|
|
284
|
+
if (endPrev > start) delta.push({ delete: endPrev - start });
|
|
285
|
+
let i = start;
|
|
286
|
+
while (i < endNext) {
|
|
287
|
+
const unit = next[i];
|
|
288
|
+
if (typeof unit.v !== "string") {
|
|
289
|
+
delta.push({ insert: unit.v, attributes: toAttributes(unit.a) });
|
|
290
|
+
i++;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
let j = i + 1;
|
|
294
|
+
let chunk = unit.v;
|
|
295
|
+
const attributes = attrsKeyOf(unit);
|
|
296
|
+
while (j < endNext && typeof next[j].v === "string" && attrsKeyOf(next[j]) === attributes) {
|
|
297
|
+
chunk += next[j].v;
|
|
298
|
+
j++;
|
|
299
|
+
}
|
|
300
|
+
delta.push({ insert: chunk, attributes: toAttributes(unit.a) });
|
|
301
|
+
i = j;
|
|
302
|
+
}
|
|
303
|
+
reformat(delta, previous, endPrev, next, endNext, previous.length - endPrev);
|
|
304
|
+
if (delta.every((op) => op.retain !== void 0 && !op.attributes)) return;
|
|
305
|
+
text.applyDelta(delta, { sanitize: false });
|
|
306
|
+
}
|
|
307
|
+
function writeUnits(text, units) {
|
|
308
|
+
applyUnits(text, [], units);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/mirror.ts
|
|
312
|
+
function isRichParagraph(map) {
|
|
313
|
+
return map.has("inline");
|
|
314
|
+
}
|
|
315
|
+
function isParagraphEl(el) {
|
|
316
|
+
return el.ns === WML && el.local === "p";
|
|
317
|
+
}
|
|
318
|
+
function fieldsOf(map, xml) {
|
|
319
|
+
map.set("ns", xml.ns);
|
|
320
|
+
map.set("local", xml.local);
|
|
321
|
+
if (xml.prefix !== void 0) map.set("prefix", xml.prefix);
|
|
322
|
+
const attrs = new Y.Array();
|
|
323
|
+
attrs.push(xml.attrs.map((a) => ({ ...a })));
|
|
324
|
+
map.set("attrs", attrs);
|
|
325
|
+
const bindings = new Y.Array();
|
|
326
|
+
bindings.push(xml.bindings.map((b) => ({ ...b })));
|
|
327
|
+
map.set("bindings", bindings);
|
|
328
|
+
}
|
|
329
|
+
function newText(value) {
|
|
330
|
+
const text = new Y.Text();
|
|
331
|
+
text.insert(0, value);
|
|
332
|
+
return text;
|
|
333
|
+
}
|
|
334
|
+
function createRichParagraph(xml, encoded) {
|
|
335
|
+
const map = new Y.Map();
|
|
336
|
+
fieldsOf(map, xml);
|
|
337
|
+
const children = new Y.Array();
|
|
338
|
+
children.push(encoded.head.map((el) => xmlToLive(el)));
|
|
339
|
+
map.set("children", children);
|
|
340
|
+
const inline = new Y.Text();
|
|
341
|
+
writeUnits(inline, encoded.units);
|
|
342
|
+
map.set("inline", inline);
|
|
343
|
+
return map;
|
|
344
|
+
}
|
|
345
|
+
function xmlToLive(xml) {
|
|
346
|
+
if (isParagraphEl(xml)) {
|
|
347
|
+
const encoded = encodeParagraph(xml.children);
|
|
348
|
+
if (encoded) return createRichParagraph(xml, encoded);
|
|
349
|
+
}
|
|
350
|
+
return xmlToGenericLive(xml);
|
|
351
|
+
}
|
|
352
|
+
function xmlToGenericLive(xml) {
|
|
353
|
+
const map = new Y.Map();
|
|
354
|
+
fieldsOf(map, xml);
|
|
355
|
+
const children = new Y.Array();
|
|
356
|
+
children.push(xml.children.map((c) => typeof c === "string" ? newText(c) : xmlToLive(c)));
|
|
357
|
+
map.set("children", children);
|
|
358
|
+
return map;
|
|
359
|
+
}
|
|
360
|
+
function liveToXml(map) {
|
|
361
|
+
const prefix = map.get("prefix");
|
|
362
|
+
const stored = map.get("children").toArray().map((child) => child instanceof Y.Text ? child.toString() : liveToXml(child));
|
|
363
|
+
const children = isRichParagraph(map) ? [...stored, ...decodeInline(readUnits(map.get("inline")))] : stored;
|
|
364
|
+
const xml = {
|
|
365
|
+
ns: map.get("ns"),
|
|
366
|
+
local: map.get("local"),
|
|
367
|
+
attrs: map.get("attrs").toArray().map((a) => ({ ...a })),
|
|
368
|
+
bindings: map.get("bindings").toArray().map((b) => ({ ...b })),
|
|
369
|
+
children
|
|
370
|
+
};
|
|
371
|
+
if (prefix !== void 0) xml.prefix = prefix;
|
|
372
|
+
return xml;
|
|
373
|
+
}
|
|
374
|
+
var escapeText = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
375
|
+
var escapeAttr = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/\t/g, "	").replace(/\n/g, " ").replace(/\r/g, " ");
|
|
376
|
+
var qualified = (prefix, local) => prefix ? `${prefix}:${local}` : local;
|
|
377
|
+
function serializeXml(el, scope) {
|
|
378
|
+
const inScope = new Map(scope);
|
|
379
|
+
for (const b of el.bindings) inScope.set(b.prefix, b.ns);
|
|
380
|
+
let out = `<${qualified(el.prefix, el.local)}`;
|
|
381
|
+
for (const b of el.bindings) {
|
|
382
|
+
out += b.prefix === "" ? ` xmlns="${escapeAttr(b.ns)}"` : ` xmlns:${b.prefix}="${escapeAttr(b.ns)}"`;
|
|
383
|
+
}
|
|
384
|
+
for (const a of el.attrs) {
|
|
385
|
+
let p = a.prefix;
|
|
386
|
+
if (a.ns !== "" && !p) {
|
|
387
|
+
for (const [candidate, uri] of inScope) {
|
|
388
|
+
if (candidate !== "" && uri === a.ns) {
|
|
389
|
+
p = candidate;
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
out += ` ${qualified(p, a.local)}="${escapeAttr(a.value)}"`;
|
|
395
|
+
}
|
|
396
|
+
if (el.children.length === 0) return `${out}/>`;
|
|
397
|
+
out += ">";
|
|
398
|
+
for (const child of el.children) {
|
|
399
|
+
out += typeof child === "string" ? escapeText(child) : serializeXml(child, inScope);
|
|
400
|
+
}
|
|
401
|
+
return `${out}</${qualified(el.prefix, el.local)}>`;
|
|
402
|
+
}
|
|
403
|
+
function serializeLive(el, scope) {
|
|
404
|
+
if (isRichParagraph(el)) return serializeXml(liveToXml(el), scope);
|
|
405
|
+
const prefix = el.get("prefix");
|
|
406
|
+
const local = el.get("local");
|
|
407
|
+
const bindings = el.get("bindings").toArray();
|
|
408
|
+
const attrs = el.get("attrs").toArray();
|
|
409
|
+
const children = el.get("children").toArray();
|
|
410
|
+
const inScope = new Map(scope);
|
|
411
|
+
for (const b of bindings) inScope.set(b.prefix, b.ns);
|
|
412
|
+
let out = `<${qualified(prefix, local)}`;
|
|
413
|
+
for (const b of bindings) {
|
|
414
|
+
out += b.prefix === "" ? ` xmlns="${escapeAttr(b.ns)}"` : ` xmlns:${b.prefix}="${escapeAttr(b.ns)}"`;
|
|
415
|
+
}
|
|
416
|
+
for (const a of attrs) {
|
|
417
|
+
let p = a.prefix;
|
|
418
|
+
if (a.ns !== "" && !p) {
|
|
419
|
+
for (const [candidate, uri] of inScope) {
|
|
420
|
+
if (candidate !== "" && uri === a.ns) {
|
|
421
|
+
p = candidate;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
out += ` ${qualified(p, a.local)}="${escapeAttr(a.value)}"`;
|
|
427
|
+
}
|
|
428
|
+
if (children.length === 0) return `${out}/>`;
|
|
429
|
+
out += ">";
|
|
430
|
+
for (const child of children) {
|
|
431
|
+
out += child instanceof Y.Text ? escapeText(child.toString()) : serializeLive(child, inScope);
|
|
432
|
+
}
|
|
433
|
+
return `${out}</${qualified(prefix, local)}>`;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/encoding.ts
|
|
437
|
+
var COLLAB_FORMAT = "arbi-docx/1";
|
|
438
|
+
function isText(node) {
|
|
439
|
+
return node.kind === "textValue";
|
|
440
|
+
}
|
|
441
|
+
function canonicalToXml(node) {
|
|
442
|
+
if (isText(node)) return node.value;
|
|
443
|
+
const xml = {
|
|
444
|
+
ns: node.namespaceUri,
|
|
445
|
+
local: node.localName,
|
|
446
|
+
attrs: node.attributes.map((a) => {
|
|
447
|
+
const json = { ns: a.namespaceUri, local: a.localName, value: a.value };
|
|
448
|
+
if (a.prefix !== void 0) json.prefix = a.prefix;
|
|
449
|
+
return json;
|
|
450
|
+
}),
|
|
451
|
+
bindings: node.namespaceBindings.map((b) => ({ prefix: b.prefix, ns: b.namespaceUri })),
|
|
452
|
+
children: node.children.map(canonicalToXml)
|
|
453
|
+
};
|
|
454
|
+
if (node.prefix !== void 0) xml.prefix = node.prefix;
|
|
455
|
+
return xml;
|
|
456
|
+
}
|
|
457
|
+
function encodeElement(el) {
|
|
458
|
+
return xmlToLive(canonicalToXml(el));
|
|
459
|
+
}
|
|
460
|
+
function encodeText(value) {
|
|
461
|
+
return newText(value);
|
|
462
|
+
}
|
|
463
|
+
function bootstrap(doc, pkg) {
|
|
464
|
+
doc.transact(() => {
|
|
465
|
+
const meta = doc.getMap("meta");
|
|
466
|
+
meta.set("format", COLLAB_FORMAT);
|
|
467
|
+
meta.set("mainDocumentPart", pkg.mainDocumentPart);
|
|
468
|
+
const parts = doc.getMap("parts");
|
|
469
|
+
for (const [name, part] of pkg.parts) {
|
|
470
|
+
if (isRelsPart(name)) continue;
|
|
471
|
+
parts.set(name, encodeElement(part.root));
|
|
472
|
+
}
|
|
473
|
+
const binaries = doc.getMap("binaries");
|
|
474
|
+
for (const [name, bytes] of pkg.partBytes) {
|
|
475
|
+
if (!pkg.parts.has(name)) binaries.set(name, bytes);
|
|
476
|
+
}
|
|
477
|
+
const rels = doc.getMap("rels");
|
|
478
|
+
for (const [owner, records] of pkg.relationships) {
|
|
479
|
+
const byId = new Y.Map();
|
|
480
|
+
for (const r of records) {
|
|
481
|
+
byId.set(r.id, {
|
|
482
|
+
ownerPart: r.ownerPart,
|
|
483
|
+
id: r.id,
|
|
484
|
+
type: r.type,
|
|
485
|
+
rawTarget: r.rawTarget,
|
|
486
|
+
targetMode: r.targetMode,
|
|
487
|
+
order: r.order
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
rels.set(owner, byId);
|
|
491
|
+
}
|
|
492
|
+
for (const e of pkg.externalTargets) {
|
|
493
|
+
let byId = rels.get(e.ownerPart);
|
|
494
|
+
if (!byId) {
|
|
495
|
+
byId = new Y.Map();
|
|
496
|
+
rels.set(e.ownerPart, byId);
|
|
497
|
+
}
|
|
498
|
+
byId.set(e.id, {
|
|
499
|
+
ownerPart: e.ownerPart,
|
|
500
|
+
id: e.id,
|
|
501
|
+
type: e.type,
|
|
502
|
+
rawTarget: e.rawTarget,
|
|
503
|
+
targetMode: "External",
|
|
504
|
+
order: byId.size
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
const ctDefaults = doc.getMap("ctDefaults");
|
|
508
|
+
for (const [ext, mime] of pkg.contentTypes.defaults) ctDefaults.set(ext, mime);
|
|
509
|
+
const ctOverrides = doc.getMap("ctOverrides");
|
|
510
|
+
for (const [name, mime] of pkg.contentTypes.overrides) ctOverrides.set(name, mime);
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
function isBootstrapped(doc) {
|
|
514
|
+
return doc.getMap("meta").get("format") !== void 0;
|
|
515
|
+
}
|
|
516
|
+
function readFormat(doc) {
|
|
517
|
+
const format = doc.getMap("meta").get("format");
|
|
518
|
+
return typeof format === "string" ? format : void 0;
|
|
519
|
+
}
|
|
520
|
+
function serializePart(doc, partName) {
|
|
521
|
+
const root = doc.getMap("parts").get(partName);
|
|
522
|
+
if (!root) throw new Error(`collab: part ${partName} is not in the room`);
|
|
523
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
524
|
+
${serializeLive(root, /* @__PURE__ */ new Map())}`;
|
|
525
|
+
}
|
|
526
|
+
function contentTypeOf(doc, partName) {
|
|
527
|
+
const override = doc.getMap("ctOverrides").get(partName.toLowerCase());
|
|
528
|
+
if (override !== void 0) return override;
|
|
529
|
+
const dot = partName.lastIndexOf(".");
|
|
530
|
+
if (dot < 0) return void 0;
|
|
531
|
+
return doc.getMap("ctDefaults").get(partName.slice(dot + 1).toLowerCase());
|
|
532
|
+
}
|
|
533
|
+
function registerMirror(doc, registry, only) {
|
|
534
|
+
const parts = doc.getMap("parts");
|
|
535
|
+
if (!only) {
|
|
536
|
+
registry.clear();
|
|
537
|
+
for (const [name, root] of parts) registry.registerTree(name, root);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
for (const name of only) {
|
|
541
|
+
registry.dropPart(name);
|
|
542
|
+
const root = parts.get(name);
|
|
543
|
+
if (root) registry.registerTree(name, root);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
var MaterializeCache = class {
|
|
547
|
+
parts = /* @__PURE__ */ new Map();
|
|
548
|
+
dirty = /* @__PURE__ */ new Set();
|
|
549
|
+
everything = true;
|
|
550
|
+
stop = [];
|
|
551
|
+
constructor(doc) {
|
|
552
|
+
const parts = doc.getMap("parts");
|
|
553
|
+
const onParts = (events) => {
|
|
554
|
+
for (const event of events) {
|
|
555
|
+
if (event.target === parts) {
|
|
556
|
+
for (const key of event.keysChanged) this.dirty.add(key);
|
|
557
|
+
} else if (typeof event.path[0] === "string") this.dirty.add(event.path[0]);
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
parts.observeDeep(onParts);
|
|
561
|
+
this.stop.push(() => parts.unobserveDeep(onParts));
|
|
562
|
+
for (const name of ["ctOverrides", "ctDefaults"]) {
|
|
563
|
+
const map = doc.getMap(name);
|
|
564
|
+
const onTypes = () => {
|
|
565
|
+
this.everything = true;
|
|
566
|
+
};
|
|
567
|
+
map.observe(onTypes);
|
|
568
|
+
this.stop.push(() => map.unobserve(onTypes));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** Names to re-read, or null when everything must be. Clears the pending set. */
|
|
572
|
+
take() {
|
|
573
|
+
const names = this.everything ? null : this.dirty;
|
|
574
|
+
this.dirty = /* @__PURE__ */ new Set();
|
|
575
|
+
this.everything = false;
|
|
576
|
+
return names;
|
|
577
|
+
}
|
|
578
|
+
/** Mark parts changed again, for a materialisation that did not complete. */
|
|
579
|
+
restore(names) {
|
|
580
|
+
if (names === null) this.everything = true;
|
|
581
|
+
else for (const name of names) this.dirty.add(name);
|
|
582
|
+
}
|
|
583
|
+
destroy() {
|
|
584
|
+
for (const stop of this.stop.splice(0)) stop();
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
var RELS_CONTENT_TYPE = "application/vnd.openxmlformats-package.relationships+xml";
|
|
588
|
+
var RELS_NAMESPACE = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
589
|
+
function isRelsPart(partName) {
|
|
590
|
+
return partName.endsWith(".rels");
|
|
591
|
+
}
|
|
592
|
+
function relationshipsXml(records) {
|
|
593
|
+
const rows = records.map(
|
|
594
|
+
(r) => `<Relationship Id="${escapeAttr(r.id)}" Type="${escapeAttr(r.type)}" Target="${escapeAttr(r.rawTarget)}"${r.targetMode === "External" ? ' TargetMode="External"' : ""}/>`
|
|
595
|
+
).join("");
|
|
596
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
597
|
+
<Relationships xmlns="${RELS_NAMESPACE}">${rows}</Relationships>`;
|
|
598
|
+
}
|
|
599
|
+
var MaterializeError = class extends Error {
|
|
600
|
+
constructor(message) {
|
|
601
|
+
super(message);
|
|
602
|
+
this.name = "MaterializeError";
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
function materialize(doc, cache, changed = null) {
|
|
606
|
+
const meta = doc.getMap("meta");
|
|
607
|
+
const main = meta.get("mainDocumentPart");
|
|
608
|
+
if (typeof main !== "string") throw new MaterializeError("room has no main document part");
|
|
609
|
+
const parts = /* @__PURE__ */ new Map();
|
|
610
|
+
for (const name of doc.getMap("parts").keys()) {
|
|
611
|
+
if (isRelsPart(name)) continue;
|
|
612
|
+
const reusable = cache && changed && !changed.has(name) ? cache.parts.get(name) : void 0;
|
|
613
|
+
if (reusable) {
|
|
614
|
+
parts.set(name, reusable);
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
const contentType = contentTypeOf(doc, name);
|
|
618
|
+
if (contentType === void 0) throw new MaterializeError(`part ${name} has no content type`);
|
|
619
|
+
const read = readOoxmlPart(serializePart(doc, name), { name, contentType });
|
|
620
|
+
if (!read.ok) throw new MaterializeError(`part ${name} is not readable: ${read.reason}`);
|
|
621
|
+
parts.set(name, read.part);
|
|
622
|
+
}
|
|
623
|
+
if (cache) {
|
|
624
|
+
cache.parts.clear();
|
|
625
|
+
for (const [name, part] of parts) if (!isRelsPart(name)) cache.parts.set(name, part);
|
|
626
|
+
}
|
|
627
|
+
const partBytes = /* @__PURE__ */ new Map();
|
|
628
|
+
for (const [name, bytes] of doc.getMap("binaries")) partBytes.set(name, bytes);
|
|
629
|
+
const relationships = /* @__PURE__ */ new Map();
|
|
630
|
+
const externalTargets = [];
|
|
631
|
+
for (const [owner, byId] of doc.getMap("rels")) {
|
|
632
|
+
const records = [...byId.values()].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
|
|
633
|
+
if (records.length === 0) continue;
|
|
634
|
+
const internal = records.filter((r) => r.targetMode !== "External");
|
|
635
|
+
if (internal.length > 0) relationships.set(owner, internal);
|
|
636
|
+
for (const r of records) {
|
|
637
|
+
if (r.targetMode !== "External") continue;
|
|
638
|
+
externalTargets.push({
|
|
639
|
+
ownerPart: r.ownerPart,
|
|
640
|
+
id: r.id,
|
|
641
|
+
type: r.type,
|
|
642
|
+
rawTarget: r.rawTarget,
|
|
643
|
+
sinkSafe: validateExternalTarget(r.rawTarget).ok
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
const relsName = relsPartNameFor(owner);
|
|
647
|
+
const read = readOoxmlPart(relationshipsXml(records), {
|
|
648
|
+
name: relsName,
|
|
649
|
+
contentType: RELS_CONTENT_TYPE
|
|
650
|
+
});
|
|
651
|
+
if (!read.ok)
|
|
652
|
+
throw new MaterializeError(`relationships of ${owner} are not valid: ${read.reason}`);
|
|
653
|
+
parts.set(relsName, read.part);
|
|
654
|
+
}
|
|
655
|
+
const contentTypes = {
|
|
656
|
+
defaults: new Map(doc.getMap("ctDefaults")),
|
|
657
|
+
overrides: new Map(doc.getMap("ctOverrides"))
|
|
658
|
+
};
|
|
659
|
+
return {
|
|
660
|
+
parts,
|
|
661
|
+
partBytes,
|
|
662
|
+
relationships,
|
|
663
|
+
externalTargets,
|
|
664
|
+
contentTypes,
|
|
665
|
+
mainDocumentPart: main
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
function materializeBytes(doc) {
|
|
669
|
+
return writeOoxmlPackage(materialize(doc));
|
|
670
|
+
}
|
|
671
|
+
function bootstrapFromBytes(doc, bytes) {
|
|
672
|
+
const result = readOoxmlPackage(bytes);
|
|
673
|
+
if (!result.ok) throw new MaterializeError(`not a readable DOCX: ${result.reason}`);
|
|
674
|
+
bootstrap(doc, result.package);
|
|
675
|
+
return result.package;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
export { COLLAB_FORMAT, MaterializeCache, MaterializeError, bootstrap, bootstrapFromBytes, contentTypeOf, encodeElement, encodeText, isBootstrapped, materialize, materializeBytes, readFormat, registerMirror, serializePart };
|
|
679
|
+
//# sourceMappingURL=encoding.js.map
|
|
680
|
+
//# sourceMappingURL=encoding.js.map
|