ooxml-core 1.22.0 → 1.24.0
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/README.md +7 -2
- package/dist/automation/index.cjs +559 -339
- package/dist/automation/index.d.ts +1 -0
- package/dist/automation/index.d.ts.map +1 -1
- package/dist/automation/index.mjs +558 -340
- package/dist/automation/live.d.ts +89 -0
- package/dist/automation/live.d.ts.map +1 -0
- package/dist/collab/embedding.d.ts +7 -0
- package/dist/collab/embedding.d.ts.map +1 -1
- package/dist/collab/index.cjs +189 -0
- package/dist/collab/index.d.ts +2 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.mjs +186 -1
- package/dist/collab/write-back-lifecycle.d.ts +33 -0
- package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
- package/dist/collab/write-back.d.ts +75 -0
- package/dist/collab/write-back.d.ts.map +1 -0
- package/dist/docx/ui/customization.d.ts +30 -0
- package/dist/docx/ui/customization.d.ts.map +1 -0
- package/dist/docx/ui/index.cjs +51 -0
- package/dist/docx/ui/index.d.ts +1 -0
- package/dist/docx/ui/index.d.ts.map +1 -1
- package/dist/docx/ui/index.mjs +46 -1
- package/dist/embedding/backstage.d.ts +48 -0
- package/dist/embedding/backstage.d.ts.map +1 -0
- package/dist/embedding/capabilities.d.ts +60 -0
- package/dist/embedding/capabilities.d.ts.map +1 -0
- package/dist/embedding/customization.d.ts +32 -0
- package/dist/embedding/customization.d.ts.map +1 -0
- package/dist/embedding/index.cjs +229 -0
- package/dist/embedding/index.d.ts +7 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/index.mjs +204 -0
- package/dist/embedding/menu-commands.d.ts +66 -0
- package/dist/embedding/menu-commands.d.ts.map +1 -0
- package/dist/embedding/regions.d.ts +58 -0
- package/dist/embedding/regions.d.ts.map +1 -0
- package/dist/embedding/storage.d.ts +111 -0
- package/dist/embedding/storage.d.ts.map +1 -0
- package/dist/index.cjs +233 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +233 -1
- package/dist/visio/collab/baseline.d.ts +36 -0
- package/dist/visio/collab/baseline.d.ts.map +1 -0
- package/dist/visio/collab/bind.d.ts +20 -2
- package/dist/visio/collab/bind.d.ts.map +1 -1
- package/dist/visio/collab/compose-lists.d.ts +27 -0
- package/dist/visio/collab/compose-lists.d.ts.map +1 -0
- package/dist/visio/collab/compose.d.ts +6 -2
- package/dist/visio/collab/compose.d.ts.map +1 -1
- package/dist/visio/collab/fixups.d.ts +5 -0
- package/dist/visio/collab/fixups.d.ts.map +1 -0
- package/dist/visio/collab/index.cjs +1603 -361
- package/dist/visio/collab/index.d.ts +3 -2
- package/dist/visio/collab/index.d.ts.map +1 -1
- package/dist/visio/collab/index.mjs +1596 -362
- package/dist/visio/collab/keys.d.ts +32 -1
- package/dist/visio/collab/keys.d.ts.map +1 -1
- package/dist/visio/collab/package.d.ts +22 -1
- package/dist/visio/collab/package.d.ts.map +1 -1
- package/dist/visio/collab/pieces.d.ts +41 -0
- package/dist/visio/collab/pieces.d.ts.map +1 -0
- package/dist/visio/collab/read-ids.d.ts +35 -0
- package/dist/visio/collab/read-ids.d.ts.map +1 -0
- package/dist/visio/collab/read-parts.d.ts +34 -0
- package/dist/visio/collab/read-parts.d.ts.map +1 -0
- package/dist/visio/collab/read-shapes.d.ts +34 -0
- package/dist/visio/collab/read-shapes.d.ts.map +1 -0
- package/dist/visio/collab/read-util.d.ts +20 -0
- package/dist/visio/collab/read-util.d.ts.map +1 -0
- package/dist/visio/collab/read.d.ts +40 -19
- package/dist/visio/collab/read.d.ts.map +1 -1
- package/dist/visio/collab/schema.d.ts +55 -1
- package/dist/visio/collab/schema.d.ts.map +1 -1
- package/dist/visio/collab/snapshot-contents.d.ts +9 -0
- package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-io.d.ts +26 -0
- package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-parts.d.ts +14 -0
- package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
- package/dist/visio/collab/snapshot.d.ts +31 -24
- package/dist/visio/collab/snapshot.d.ts.map +1 -1
- package/dist/visio/collab/write-parts.d.ts +8 -0
- package/dist/visio/collab/write-parts.d.ts.map +1 -0
- package/dist/visio/collab/write-shapes.d.ts +30 -0
- package/dist/visio/collab/write-shapes.d.ts.map +1 -0
- package/dist/visio/collab/write.d.ts +4 -16
- package/dist/visio/collab/write.d.ts.map +1 -1
- package/dist/visio/collab/zip-store.d.ts +4 -0
- package/dist/visio/collab/zip-store.d.ts.map +1 -0
- package/dist/visio/document-level.d.ts +57 -0
- package/dist/visio/document-level.d.ts.map +1 -0
- package/dist/visio/index.cjs +485 -333
- package/dist/visio/index.d.ts +2 -0
- package/dist/visio/index.d.ts.map +1 -1
- package/dist/visio/index.mjs +484 -334
- package/dist/visio/layers.d.ts +3 -0
- package/dist/visio/layers.d.ts.map +1 -1
- package/dist/visio/package.d.ts +9 -0
- package/dist/visio/package.d.ts.map +1 -1
- package/dist/visio/parse-incremental.d.ts +16 -0
- package/dist/visio/parse-incremental.d.ts.map +1 -0
- package/dist/visio/parser.d.ts +14 -0
- package/dist/visio/parser.d.ts.map +1 -1
- package/dist/visio/shape-metadata.d.ts +3 -0
- package/dist/visio/shape-metadata.d.ts.map +1 -1
- package/dist/visio/ui/collab-options.d.ts +10 -5
- package/dist/visio/ui/collab-options.d.ts.map +1 -1
- package/dist/visio/ui/contract.d.ts +27 -2
- package/dist/visio/ui/contract.d.ts.map +1 -1
- package/dist/visio/ui/customization.d.ts +46 -0
- package/dist/visio/ui/customization.d.ts.map +1 -0
- package/dist/visio/ui/index.cjs +460 -320
- package/dist/visio/ui/index.d.ts +1 -0
- package/dist/visio/ui/index.d.ts.map +1 -1
- package/dist/visio/ui/index.mjs +458 -321
- package/dist/xlsx/ui/commands.d.ts +2 -0
- package/dist/xlsx/ui/commands.d.ts.map +1 -1
- package/dist/xlsx/ui/customization.d.ts +49 -0
- package/dist/xlsx/ui/customization.d.ts.map +1 -0
- package/dist/xlsx/ui/index.cjs +39 -1
- package/dist/xlsx/ui/index.d.ts +1 -0
- package/dist/xlsx/ui/index.d.ts.map +1 -1
- package/dist/xlsx/ui/index.mjs +37 -2
- package/package.json +6 -1
|
@@ -1,8 +1,145 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
-
import JSZip from 'jszip';
|
|
3
2
|
import { XMLSerializer, DOMParser } from '@xmldom/xmldom';
|
|
3
|
+
import JSZip from 'jszip';
|
|
4
4
|
|
|
5
5
|
// visio/collab/bind.ts
|
|
6
|
+
|
|
7
|
+
// digest/sha256.ts
|
|
8
|
+
var K = new Uint32Array([
|
|
9
|
+
1116352408,
|
|
10
|
+
1899447441,
|
|
11
|
+
3049323471,
|
|
12
|
+
3921009573,
|
|
13
|
+
961987163,
|
|
14
|
+
1508970993,
|
|
15
|
+
2453635748,
|
|
16
|
+
2870763221,
|
|
17
|
+
3624381080,
|
|
18
|
+
310598401,
|
|
19
|
+
607225278,
|
|
20
|
+
1426881987,
|
|
21
|
+
1925078388,
|
|
22
|
+
2162078206,
|
|
23
|
+
2614888103,
|
|
24
|
+
3248222580,
|
|
25
|
+
3835390401,
|
|
26
|
+
4022224774,
|
|
27
|
+
264347078,
|
|
28
|
+
604807628,
|
|
29
|
+
770255983,
|
|
30
|
+
1249150122,
|
|
31
|
+
1555081692,
|
|
32
|
+
1996064986,
|
|
33
|
+
2554220882,
|
|
34
|
+
2821834349,
|
|
35
|
+
2952996808,
|
|
36
|
+
3210313671,
|
|
37
|
+
3336571891,
|
|
38
|
+
3584528711,
|
|
39
|
+
113926993,
|
|
40
|
+
338241895,
|
|
41
|
+
666307205,
|
|
42
|
+
773529912,
|
|
43
|
+
1294757372,
|
|
44
|
+
1396182291,
|
|
45
|
+
1695183700,
|
|
46
|
+
1986661051,
|
|
47
|
+
2177026350,
|
|
48
|
+
2456956037,
|
|
49
|
+
2730485921,
|
|
50
|
+
2820302411,
|
|
51
|
+
3259730800,
|
|
52
|
+
3345764771,
|
|
53
|
+
3516065817,
|
|
54
|
+
3600352804,
|
|
55
|
+
4094571909,
|
|
56
|
+
275423344,
|
|
57
|
+
430227734,
|
|
58
|
+
506948616,
|
|
59
|
+
659060556,
|
|
60
|
+
883997877,
|
|
61
|
+
958139571,
|
|
62
|
+
1322822218,
|
|
63
|
+
1537002063,
|
|
64
|
+
1747873779,
|
|
65
|
+
1955562222,
|
|
66
|
+
2024104815,
|
|
67
|
+
2227730452,
|
|
68
|
+
2361852424,
|
|
69
|
+
2428436474,
|
|
70
|
+
2756734187,
|
|
71
|
+
3204031479,
|
|
72
|
+
3329325298
|
|
73
|
+
]);
|
|
74
|
+
var IV = [
|
|
75
|
+
1779033703,
|
|
76
|
+
3144134277,
|
|
77
|
+
1013904242,
|
|
78
|
+
2773480762,
|
|
79
|
+
1359893119,
|
|
80
|
+
2600822924,
|
|
81
|
+
528734635,
|
|
82
|
+
1541459225
|
|
83
|
+
];
|
|
84
|
+
var W = new Uint32Array(64);
|
|
85
|
+
var rotr = (x, n) => x >>> n | x << 32 - n;
|
|
86
|
+
function compress(h, view, offset) {
|
|
87
|
+
for (let i = 0; i < 16; i++) W[i] = view.getUint32(offset + i * 4);
|
|
88
|
+
for (let i = 16; i < 64; i++) {
|
|
89
|
+
const a2 = W[i - 15];
|
|
90
|
+
const b2 = W[i - 2];
|
|
91
|
+
const s0 = rotr(a2, 7) ^ rotr(a2, 18) ^ a2 >>> 3;
|
|
92
|
+
const s1 = rotr(b2, 17) ^ rotr(b2, 19) ^ b2 >>> 10;
|
|
93
|
+
W[i] = W[i - 16] + s0 + W[i - 7] + s1 >>> 0;
|
|
94
|
+
}
|
|
95
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], k = h[7];
|
|
96
|
+
for (let i = 0; i < 64; i++) {
|
|
97
|
+
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
98
|
+
const ch = e & f ^ ~e & g;
|
|
99
|
+
const t1 = k + S1 + ch + K[i] + W[i] >>> 0;
|
|
100
|
+
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
101
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
102
|
+
const t2 = S0 + maj >>> 0;
|
|
103
|
+
k = g;
|
|
104
|
+
g = f;
|
|
105
|
+
f = e;
|
|
106
|
+
e = d + t1 >>> 0;
|
|
107
|
+
d = c;
|
|
108
|
+
c = b;
|
|
109
|
+
b = a;
|
|
110
|
+
a = t1 + t2 >>> 0;
|
|
111
|
+
}
|
|
112
|
+
h[0] = h[0] + a >>> 0;
|
|
113
|
+
h[1] = h[1] + b >>> 0;
|
|
114
|
+
h[2] = h[2] + c >>> 0;
|
|
115
|
+
h[3] = h[3] + d >>> 0;
|
|
116
|
+
h[4] = h[4] + e >>> 0;
|
|
117
|
+
h[5] = h[5] + f >>> 0;
|
|
118
|
+
h[6] = h[6] + g >>> 0;
|
|
119
|
+
h[7] = h[7] + k >>> 0;
|
|
120
|
+
}
|
|
121
|
+
function pad64(data) {
|
|
122
|
+
const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
|
|
123
|
+
padded.set(data);
|
|
124
|
+
padded[data.length] = 128;
|
|
125
|
+
const bits = data.length * 8;
|
|
126
|
+
const view = new DataView(padded.buffer);
|
|
127
|
+
view.setUint32(padded.length - 8, Math.floor(bits / 4294967296));
|
|
128
|
+
view.setUint32(padded.length - 4, bits >>> 0);
|
|
129
|
+
return view;
|
|
130
|
+
}
|
|
131
|
+
function wordsOut(h) {
|
|
132
|
+
const out = new Uint8Array(h.length * 4);
|
|
133
|
+
const view = new DataView(out.buffer);
|
|
134
|
+
for (let i = 0; i < h.length; i++) view.setUint32(i * 4, h[i]);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
function sha256(data) {
|
|
138
|
+
const h = new Uint32Array(IV);
|
|
139
|
+
const view = pad64(data);
|
|
140
|
+
for (let offset = 0; offset < view.byteLength; offset += 64) compress(h, view, offset);
|
|
141
|
+
return wordsOut(h);
|
|
142
|
+
}
|
|
6
143
|
var DEFAULT_XML_LIMITS = {
|
|
7
144
|
maxDepth: 512,
|
|
8
145
|
maxNodes: 5e6
|
|
@@ -253,11 +390,51 @@ function stripPageOverrides(xml) {
|
|
|
253
390
|
(tag) => attrOf(tag, "ContentType") === PAGE_CONTENT_TYPE ? "" : tag
|
|
254
391
|
);
|
|
255
392
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
393
|
+
var withPageOverrides = (xml, pagePaths) => withOverrides(stripPageOverrides(xml), PAGE_CONTENT_TYPE, pagePaths);
|
|
394
|
+
var MASTER_TYPE = "http://schemas.microsoft.com/visio/2010/relationships/master";
|
|
395
|
+
var MASTER_CONTENT_TYPE = "application/vnd.ms-visio.master+xml";
|
|
396
|
+
function withOverrides(xml, contentType, paths) {
|
|
397
|
+
const add = paths.map((path) => `<Override PartName="/${path}" ContentType="${contentType}"/>`).join("");
|
|
398
|
+
const close = xml.lastIndexOf("</");
|
|
399
|
+
return close < 0 ? xml : xml.slice(0, close) + add + xml.slice(close);
|
|
400
|
+
}
|
|
401
|
+
function stripOverrides(xml, types, parts = /* @__PURE__ */ new Set()) {
|
|
402
|
+
return xml.replace(/<(?:\w+:)?Override\b[^>]*>/g, (tag) => {
|
|
403
|
+
const type = attrOf(tag, "ContentType");
|
|
404
|
+
const name = attrOf(tag, "PartName");
|
|
405
|
+
return type !== void 0 && types.includes(type) || name !== void 0 && parts.has(name.replace(/^\//, "")) ? "" : tag;
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function declaredType(xml, path) {
|
|
409
|
+
for (const tag of xml.matchAll(/<(?:\w+:)?Override\b[^>]*>/g)) {
|
|
410
|
+
const name = attrOf(tag[0], "PartName");
|
|
411
|
+
const type = attrOf(tag[0], "ContentType");
|
|
412
|
+
if (name === `/${path}` && type !== void 0) return { type, byDefault: false };
|
|
413
|
+
}
|
|
414
|
+
const ext = /\.([^./]+)$/.exec(path)?.[1]?.toLowerCase();
|
|
415
|
+
if (ext === void 0) return void 0;
|
|
416
|
+
for (const tag of xml.matchAll(/<(?:\w+:)?Default\b[^>]*>/g)) {
|
|
417
|
+
const e = attrOf(tag[0], "Extension");
|
|
418
|
+
const type = attrOf(tag[0], "ContentType");
|
|
419
|
+
if (e?.toLowerCase() === ext && type !== void 0) return { type, byDefault: true };
|
|
420
|
+
}
|
|
421
|
+
return void 0;
|
|
422
|
+
}
|
|
423
|
+
function ensureType(xml, path, declared) {
|
|
424
|
+
if (declaredType(xml, path)) return xml;
|
|
425
|
+
const close = xml.lastIndexOf("</");
|
|
426
|
+
if (close < 0) return xml;
|
|
427
|
+
const ext = /\.([^./]+)$/.exec(path)?.[1];
|
|
428
|
+
const tag = declared.byDefault && ext ? `<Default Extension="${ext}" ContentType="${declared.type}"/>` : `<Override PartName="/${path}" ContentType="${declared.type}"/>`;
|
|
429
|
+
return xml.slice(0, close) + tag + xml.slice(close);
|
|
430
|
+
}
|
|
431
|
+
var isMediaPart = (path) => /(^|\/)media\/[^/]+$/i.test(path);
|
|
432
|
+
function relativeTarget(dir, path) {
|
|
433
|
+
const from = dir ? dir.split("/") : [];
|
|
434
|
+
const to = path.split("/");
|
|
435
|
+
let i = 0;
|
|
436
|
+
while (i < from.length && i < to.length - 1 && from[i] === to[i]) i++;
|
|
437
|
+
return [...from.slice(i).map(() => ".."), ...to.slice(i)].join("/");
|
|
261
438
|
}
|
|
262
439
|
function toBase64(bytes) {
|
|
263
440
|
let out = "";
|
|
@@ -291,15 +468,154 @@ function canon(xml) {
|
|
|
291
468
|
canonCache.set(xml, result);
|
|
292
469
|
return result;
|
|
293
470
|
}
|
|
471
|
+
function contentHash(bytes) {
|
|
472
|
+
let out = "";
|
|
473
|
+
for (const byte of sha256(bytes)) out += byte.toString(16).padStart(2, "0");
|
|
474
|
+
return out;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// visio/collab/pieces.ts
|
|
478
|
+
var seg = (value) => value.replace(/[%/]/g, (c) => c === "%" ? "%25" : "%2F");
|
|
479
|
+
var tagName = (open) => /^<([^\s/>]+)/.exec(open)?.[1] ?? "Shape";
|
|
480
|
+
var openTagOf = (text, span) => {
|
|
481
|
+
const tag = text.slice(span.start, span.openEnd);
|
|
482
|
+
return span.selfClosing ? tag.replace(/\s*\/>$/, ">") : tag;
|
|
483
|
+
};
|
|
484
|
+
var closeTagOf = (open) => `</${tagName(open)}>`;
|
|
485
|
+
function splitShape(xml) {
|
|
486
|
+
const box = scanContainer(xml, "Shape");
|
|
487
|
+
if (!box) return void 0;
|
|
488
|
+
const used = /* @__PURE__ */ new Set();
|
|
489
|
+
const unique = (path) => {
|
|
490
|
+
let out = path;
|
|
491
|
+
for (let n = 2; used.has(out); n++) out = `${path}~${n}`;
|
|
492
|
+
used.add(out);
|
|
493
|
+
return out;
|
|
494
|
+
};
|
|
495
|
+
const pieces = [];
|
|
496
|
+
const nested = [];
|
|
497
|
+
const others = /* @__PURE__ */ new Map();
|
|
498
|
+
const other = (parent, name, text) => {
|
|
499
|
+
const k = others.get(parent + name) ?? 0;
|
|
500
|
+
others.set(parent + name, k + 1);
|
|
501
|
+
pieces.push({
|
|
502
|
+
path: unique(`${parent ? `${parent}/` : ""}x/${name}#${k}`),
|
|
503
|
+
parent,
|
|
504
|
+
kind: "leaf",
|
|
505
|
+
text
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
const cell = (parent, text) => {
|
|
509
|
+
const n = attrOf(text.slice(0, text.search(/>/) + 1), "N");
|
|
510
|
+
if (n === void 0) return other(parent, "Cell", text);
|
|
511
|
+
pieces.push({
|
|
512
|
+
path: unique(`${parent ? `${parent}/` : ""}c/${seg(n)}`),
|
|
513
|
+
parent,
|
|
514
|
+
kind: "leaf",
|
|
515
|
+
text
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
for (const child of box.children) {
|
|
519
|
+
const text = xml.slice(child.start, child.end);
|
|
520
|
+
if (child.name === "Cell") cell("", text);
|
|
521
|
+
else if (child.name === "Shapes") {
|
|
522
|
+
const list = scanContainer(text, "Shapes");
|
|
523
|
+
for (const s of list?.children ?? [])
|
|
524
|
+
if (s.name === "Shape") nested.push(text.slice(s.start, s.end));
|
|
525
|
+
} else if (child.name === "Section") {
|
|
526
|
+
const head = openTagOf(xml, child);
|
|
527
|
+
const n = attrOf(head, "N");
|
|
528
|
+
const ix = attrOf(head, "IX");
|
|
529
|
+
if (n === void 0 && ix === void 0) {
|
|
530
|
+
other("", "Section", text);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const sec = unique(`s/${seg(n ?? "")}${ix !== void 0 ? `:${seg(ix)}` : ""}`);
|
|
534
|
+
pieces.push({ path: sec, parent: "", kind: "open", text: head });
|
|
535
|
+
const inner = scanContainer(text, "Section");
|
|
536
|
+
let rowIndex = 0;
|
|
537
|
+
for (const part of inner?.children ?? []) {
|
|
538
|
+
const sub = text.slice(part.start, part.end);
|
|
539
|
+
if (part.name === "Cell") cell(sec, sub);
|
|
540
|
+
else if (part.name === "Row") {
|
|
541
|
+
const rowHead = openTagOf(text, part);
|
|
542
|
+
const id = attrOf(rowHead, "IX") ?? attrOf(rowHead, "N") ?? `#${rowIndex}`;
|
|
543
|
+
rowIndex++;
|
|
544
|
+
const row = unique(`${sec}/r/${seg(id)}`);
|
|
545
|
+
pieces.push({ path: row, parent: sec, kind: "open", text: rowHead });
|
|
546
|
+
for (const rc of scanContainer(sub, "Row")?.children ?? [])
|
|
547
|
+
if (rc.name === "Cell") cell(row, sub.slice(rc.start, rc.end));
|
|
548
|
+
else other(row, rc.name, sub.slice(rc.start, rc.end));
|
|
549
|
+
} else other(sec, part.name, sub);
|
|
550
|
+
}
|
|
551
|
+
} else other("", child.name, text);
|
|
552
|
+
}
|
|
553
|
+
return { open: openTagOf(xml, box), pieces, nested };
|
|
554
|
+
}
|
|
555
|
+
function buildShape(open, entries, tail) {
|
|
556
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
557
|
+
for (const [path, entry] of entries) {
|
|
558
|
+
const parent = parentOf(path);
|
|
559
|
+
const list = byParent.get(parent) ?? [];
|
|
560
|
+
list.push({ path, entry });
|
|
561
|
+
byParent.set(parent, list);
|
|
562
|
+
}
|
|
563
|
+
const render = (parent) => (byParent.get(parent) ?? []).sort((a, b) => a.entry.pos - b.entry.pos || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)).map(
|
|
564
|
+
({ path, entry }) => entry.open !== void 0 ? entry.open + render(path) + closeTagOf(entry.open) : entry.xml ?? ""
|
|
565
|
+
).join("");
|
|
566
|
+
return open + render("") + tail + closeTagOf(open);
|
|
567
|
+
}
|
|
568
|
+
function parentOf(path) {
|
|
569
|
+
const parts = path.split("/");
|
|
570
|
+
return parts.length <= 2 ? "" : parts.slice(0, -2).join("/");
|
|
571
|
+
}
|
|
572
|
+
var SIMPLE = /^<([^\s/>]+)((?:\s+[^\s=/>]+\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(?:\/>|>([^<]*)<\/\1>)$/;
|
|
573
|
+
var ATTR = /\s([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
574
|
+
function pieceContent(kind, text) {
|
|
575
|
+
const simple = SIMPLE.exec(kind === "open" ? `${text}</${tagName(text)}>` : text);
|
|
576
|
+
if (!simple) return kind === "open" ? canon(`${text}</${tagName(text)}>`) : canon(text);
|
|
577
|
+
const attrs = [...(simple[2] ?? "").matchAll(ATTR)].map((m) => [m[1], m[2] ?? m[3] ?? ""]).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
578
|
+
return JSON.stringify([simple[1], attrs, simple[3] ?? ""]);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// visio/collab/baseline.ts
|
|
582
|
+
var masterScope = (key) => `m~${key}`;
|
|
583
|
+
var pageId = (key) => `p:${key}`;
|
|
584
|
+
var bodyId = (key) => `b:${key}`;
|
|
585
|
+
var shapeId = (page, key) => `s:${page}/${key}`;
|
|
586
|
+
var cellId = (page, shape, path) => `f:${page}/${shape}/${path}`;
|
|
587
|
+
var connectId = (key) => `c:${key}`;
|
|
588
|
+
var masterId = (key) => `m:${key}`;
|
|
589
|
+
var mediaId = (key) => `i:${key}`;
|
|
590
|
+
var pageContent = (e) => JSON.stringify([e.id, e.back ?? null, canon(e.xml)]);
|
|
591
|
+
var bodyContent = (e) => JSON.stringify([canon(e.shell), e.rels ?? null]);
|
|
592
|
+
var shellContent = (e) => JSON.stringify([e.parent ?? null, pieceContent("open", e.open)]);
|
|
593
|
+
var entryContent = (e) => e.xml !== void 0 ? pieceContent("leaf", e.xml) : pieceContent("open", e.open ?? "");
|
|
594
|
+
var masterContent = (e) => JSON.stringify([e.id, canon(e.xml), e.rels ?? null, e.print]);
|
|
294
595
|
|
|
295
596
|
// visio/collab/schema.ts
|
|
296
|
-
var SCHEMA_VERSION =
|
|
597
|
+
var SCHEMA_VERSION = 4;
|
|
598
|
+
var SchemaVersionError = class extends Error {
|
|
599
|
+
constructor(found) {
|
|
600
|
+
super(
|
|
601
|
+
`The shared drawing uses schema version ${String(found)}; this build reads version ${SCHEMA_VERSION}.`
|
|
602
|
+
);
|
|
603
|
+
this.found = found;
|
|
604
|
+
this.name = "SchemaVersionError";
|
|
605
|
+
}
|
|
606
|
+
found;
|
|
607
|
+
};
|
|
297
608
|
var META = "visio:meta";
|
|
298
609
|
var PAGES = "visio:pages";
|
|
299
610
|
var BODIES = "visio:bodies";
|
|
300
611
|
var SHAPES = "visio:shapes";
|
|
612
|
+
var CELLS = "visio:cells";
|
|
301
613
|
var CONNECTS = "visio:connects";
|
|
302
614
|
var DEAD = "visio:dead";
|
|
615
|
+
var MASTERS = "visio:masters";
|
|
616
|
+
var RENUM = "visio:renum";
|
|
617
|
+
var MEDIA = "visio:media";
|
|
618
|
+
var BLOBS = "visio:blobs";
|
|
303
619
|
var PARTS = "visio:parts";
|
|
304
620
|
var REL_MARK = "<!--@rel-->";
|
|
305
621
|
var SHAPES_MARK = "<!--@shapes-->";
|
|
@@ -310,8 +626,13 @@ function sharedDrawing(doc) {
|
|
|
310
626
|
pages: doc.getMap(PAGES),
|
|
311
627
|
bodies: doc.getMap(BODIES),
|
|
312
628
|
shapes: doc.getMap(SHAPES),
|
|
629
|
+
cells: doc.getMap(CELLS),
|
|
313
630
|
connects: doc.getMap(CONNECTS),
|
|
314
631
|
dead: doc.getMap(DEAD),
|
|
632
|
+
masters: doc.getMap(MASTERS),
|
|
633
|
+
renum: doc.getMap(RENUM),
|
|
634
|
+
media: doc.getMap(MEDIA),
|
|
635
|
+
blobs: doc.getMap(BLOBS),
|
|
315
636
|
parts: doc.getMap(PARTS)
|
|
316
637
|
};
|
|
317
638
|
}
|
|
@@ -320,17 +641,27 @@ var sharedTypes = (shared) => [
|
|
|
320
641
|
shared.pages,
|
|
321
642
|
shared.bodies,
|
|
322
643
|
shared.shapes,
|
|
644
|
+
shared.cells,
|
|
323
645
|
shared.connects,
|
|
324
646
|
shared.dead,
|
|
647
|
+
shared.masters,
|
|
648
|
+
shared.renum,
|
|
649
|
+
shared.media,
|
|
650
|
+
shared.blobs,
|
|
325
651
|
shared.parts
|
|
326
652
|
];
|
|
327
653
|
var isSharedDrawingEmpty = (shared) => shared.pages.size === 0 && shared.meta.get("v") === void 0;
|
|
654
|
+
function assertSchemaVersion(shared) {
|
|
655
|
+
const v = shared.meta.get("v");
|
|
656
|
+
if (v !== void 0 && v !== SCHEMA_VERSION) throw new SchemaVersionError(v);
|
|
657
|
+
}
|
|
328
658
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
329
659
|
function sameRecord(a, b) {
|
|
330
660
|
if (!isRecord(a) || !isRecord(b)) return a === b;
|
|
331
661
|
const ka = Object.keys(a).filter((k) => a[k] !== void 0);
|
|
332
662
|
const kb = Object.keys(b).filter((k) => b[k] !== void 0);
|
|
333
|
-
|
|
663
|
+
const same = (x, y) => x === y || Array.isArray(x) && Array.isArray(y) && JSON.stringify(x) === JSON.stringify(y);
|
|
664
|
+
return ka.length === kb.length && ka.every((k) => same(a[k], b[k]));
|
|
334
665
|
}
|
|
335
666
|
function setIfChanged(map, key, value) {
|
|
336
667
|
if (sameRecord(map.get(key), value)) return false;
|
|
@@ -339,27 +670,59 @@ function setIfChanged(map, key, value) {
|
|
|
339
670
|
}
|
|
340
671
|
var str = (value) => typeof value === "string" ? value : void 0;
|
|
341
672
|
var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
673
|
+
var opt = (key, value) => value === void 0 ? {} : { [key]: value };
|
|
342
674
|
function pageEntry(value) {
|
|
343
675
|
if (!isRecord(value)) return void 0;
|
|
344
676
|
const pos = num(value.pos);
|
|
345
677
|
const id = str(value.id);
|
|
346
678
|
const xml = str(value.xml);
|
|
347
679
|
if (pos === void 0 || id === void 0 || xml === void 0) return void 0;
|
|
348
|
-
|
|
349
|
-
return { pos, id, xml, ...back !== void 0 ? { back } : {} };
|
|
680
|
+
return { pos, id, xml, ...opt("back", str(value.back)) };
|
|
350
681
|
}
|
|
351
682
|
function bodyEntry(value) {
|
|
352
683
|
if (!isRecord(value)) return void 0;
|
|
353
684
|
const shell = str(value.shell);
|
|
354
685
|
if (shell === void 0) return void 0;
|
|
355
|
-
|
|
356
|
-
return { shell, ...rels !== void 0 ? { rels } : {} };
|
|
686
|
+
return { shell, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
|
|
357
687
|
}
|
|
358
688
|
function shapeEntry(value) {
|
|
689
|
+
if (!isRecord(value)) return void 0;
|
|
690
|
+
const pos = num(value.pos);
|
|
691
|
+
const open = str(value.open);
|
|
692
|
+
if (pos === void 0 || open === void 0) return void 0;
|
|
693
|
+
return { pos, open, ...opt("parent", str(value.parent)), ...opt("b", str(value.b)) };
|
|
694
|
+
}
|
|
695
|
+
function cellEntry(value) {
|
|
359
696
|
if (!isRecord(value)) return void 0;
|
|
360
697
|
const pos = num(value.pos);
|
|
361
698
|
const xml = str(value.xml);
|
|
362
|
-
|
|
699
|
+
const open = str(value.open);
|
|
700
|
+
if (pos === void 0 || xml === void 0 && open === void 0) return void 0;
|
|
701
|
+
const r = Array.isArray(value.r) && value.r.length % 2 === 0 && value.r.every((v) => typeof v === "string") ? value.r : void 0;
|
|
702
|
+
return {
|
|
703
|
+
pos,
|
|
704
|
+
...opt("xml", xml),
|
|
705
|
+
...opt("open", xml === void 0 ? open : void 0),
|
|
706
|
+
...r && r.length ? { r } : {}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
function masterEntry(value) {
|
|
710
|
+
if (!isRecord(value)) return void 0;
|
|
711
|
+
const pos = num(value.pos);
|
|
712
|
+
const id = str(value.id);
|
|
713
|
+
const xml = str(value.xml);
|
|
714
|
+
const part = str(value.part);
|
|
715
|
+
if (pos === void 0 || id === void 0 || xml === void 0 || part === void 0)
|
|
716
|
+
return void 0;
|
|
717
|
+
return { pos, id, xml, part, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
|
|
718
|
+
}
|
|
719
|
+
function mediaEntry(value) {
|
|
720
|
+
if (!isRecord(value)) return void 0;
|
|
721
|
+
const path = str(value.path);
|
|
722
|
+
const hash = str(value.hash);
|
|
723
|
+
const ct = str(value.ct);
|
|
724
|
+
if (path === void 0 || hash === void 0 || ct === void 0) return void 0;
|
|
725
|
+
return { path, hash, ct, d: value.d === true, ...opt("b", str(value.b)) };
|
|
363
726
|
}
|
|
364
727
|
function connectEntry(value) {
|
|
365
728
|
if (!isRecord(value)) return void 0;
|
|
@@ -371,11 +734,15 @@ function connectEntry(value) {
|
|
|
371
734
|
}
|
|
372
735
|
return out;
|
|
373
736
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
737
|
+
function renumEntry(value) {
|
|
738
|
+
if (!isRecord(value)) return void 0;
|
|
739
|
+
const pair = (v) => Array.isArray(v) && v.length === 2 && typeof v[0] === "string" && typeof v[1] === "string" ? [v[0], v[1]] : void 0;
|
|
740
|
+
const i = pair(value.i);
|
|
741
|
+
const m = pair(value.m);
|
|
742
|
+
return i || m ? { ...i ? { i } : {}, ...m ? { m } : {} } : void 0;
|
|
378
743
|
}
|
|
744
|
+
|
|
745
|
+
// visio/collab/snapshot-contents.ts
|
|
379
746
|
function splitList(text, name, mark, child) {
|
|
380
747
|
const box = scanContainer(text, name);
|
|
381
748
|
if (!box) return { text, items: [] };
|
|
@@ -391,6 +758,66 @@ function splitList(text, name, mark, child) {
|
|
|
391
758
|
}
|
|
392
759
|
return { text: text.slice(0, box.openEnd) + mark + text.slice(box.closeStart), items };
|
|
393
760
|
}
|
|
761
|
+
function formulaRefs(text, owner) {
|
|
762
|
+
const out = [];
|
|
763
|
+
const seen = /* @__PURE__ */ new Set();
|
|
764
|
+
for (const f of text.matchAll(/\sF\s*=\s*("[^"]*"|'[^']*')/g))
|
|
765
|
+
for (const m of f[1].matchAll(/Sheet\.(\d+)(?!\d)/g)) {
|
|
766
|
+
const id = m[1];
|
|
767
|
+
const key = owner.get(id);
|
|
768
|
+
if (key !== void 0 && !seen.has(id)) {
|
|
769
|
+
seen.add(id);
|
|
770
|
+
out.push(id, key);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return out;
|
|
774
|
+
}
|
|
775
|
+
function flatten(xml, parent, page, keys, out) {
|
|
776
|
+
const split2 = splitShape(xml);
|
|
777
|
+
const id = split2 ? attrOf(split2.open, "ID") : void 0;
|
|
778
|
+
if (!split2 || id === void 0) return;
|
|
779
|
+
const key = keys.shapeKey(page, id);
|
|
780
|
+
out.push({
|
|
781
|
+
key,
|
|
782
|
+
id,
|
|
783
|
+
...parent !== void 0 ? { parent } : {},
|
|
784
|
+
open: split2.open,
|
|
785
|
+
pieces: split2.pieces
|
|
786
|
+
});
|
|
787
|
+
for (const nested of split2.nested) flatten(nested, key, page, keys, out);
|
|
788
|
+
}
|
|
789
|
+
function splitContents(content, scope, keys) {
|
|
790
|
+
const shapesSplit = splitList(content, "Shapes", SHAPES_MARK, "Shape");
|
|
791
|
+
const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
|
|
792
|
+
const shapes = [];
|
|
793
|
+
for (const text of shapesSplit.items) flatten(text, void 0, scope, keys, shapes);
|
|
794
|
+
const owner = new Map(shapes.map((s) => [s.id, s.key]));
|
|
795
|
+
for (const shape of shapes)
|
|
796
|
+
for (const piece of shape.pieces)
|
|
797
|
+
if (piece.kind === "leaf") {
|
|
798
|
+
const refs = formulaRefs(piece.text, owner);
|
|
799
|
+
if (refs.length) piece.refs = refs;
|
|
800
|
+
}
|
|
801
|
+
const connects = [];
|
|
802
|
+
for (const text of connectsSplit.items) {
|
|
803
|
+
const a = (name) => attrOf(text, name) ?? "";
|
|
804
|
+
const entry = {
|
|
805
|
+
fk: owner.get(a("FromSheet")) ?? "",
|
|
806
|
+
fi: a("FromSheet"),
|
|
807
|
+
tk: owner.get(a("ToSheet")) ?? "",
|
|
808
|
+
ti: a("ToSheet"),
|
|
809
|
+
fc: a("FromCell"),
|
|
810
|
+
tc: a("ToCell"),
|
|
811
|
+
fp: a("FromPart"),
|
|
812
|
+
tp: a("ToPart")
|
|
813
|
+
};
|
|
814
|
+
connects.push({
|
|
815
|
+
key: `${scope}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
|
|
816
|
+
entry
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
return { shell: connectsSplit.text, shapes, connects };
|
|
820
|
+
}
|
|
394
821
|
var readZip = (bytes) => JSZip.loadAsync(bytes);
|
|
395
822
|
var zipText = async (zip, path) => zip.file(path)?.async("string");
|
|
396
823
|
async function readLayout(zip) {
|
|
@@ -401,19 +828,25 @@ async function readLayout(zip) {
|
|
|
401
828
|
const documentPath = resolveTarget("", root.target);
|
|
402
829
|
const rels = parseRelationships(await zipText(zip, relsPathOf(documentPath)));
|
|
403
830
|
const pages = rels.find((r) => r.type.endsWith("/pages"));
|
|
404
|
-
|
|
831
|
+
const masters = rels.find((r) => r.type.endsWith("/masters"));
|
|
832
|
+
const dir = dirName(documentPath);
|
|
833
|
+
return pages ? {
|
|
834
|
+
documentPath,
|
|
835
|
+
pagesPath: resolveTarget(dir, pages.target),
|
|
836
|
+
...masters ? { mastersPath: resolveTarget(dir, masters.target) } : {}
|
|
837
|
+
} : void 0;
|
|
405
838
|
}
|
|
406
|
-
async function
|
|
407
|
-
const box = scanContainer(
|
|
839
|
+
async function readLocalItems(zip, listPath, xml, container, child) {
|
|
840
|
+
const box = scanContainer(xml, container);
|
|
408
841
|
if (!box) return void 0;
|
|
409
842
|
const rels = new Map(
|
|
410
|
-
parseRelationships(await zipText(zip, relsPathOf(
|
|
843
|
+
parseRelationships(await zipText(zip, relsPathOf(listPath))).map((r) => [r.id, r])
|
|
411
844
|
);
|
|
412
|
-
const
|
|
845
|
+
const items = [];
|
|
413
846
|
for (const span of box.children) {
|
|
414
|
-
if (span.name !==
|
|
415
|
-
const text =
|
|
416
|
-
const inner = scanContainer(text,
|
|
847
|
+
if (span.name !== child) continue;
|
|
848
|
+
const text = xml.slice(span.start, span.end);
|
|
849
|
+
const inner = scanContainer(text, child);
|
|
417
850
|
const relSpan = inner?.children.find((c) => c.name === "Rel");
|
|
418
851
|
if (!inner || !relSpan) return void 0;
|
|
419
852
|
const relTag = text.slice(relSpan.start, relSpan.openEnd);
|
|
@@ -421,239 +854,268 @@ async function readLocalPages(zip, layout, pagesXml) {
|
|
|
421
854
|
const target = rid ? rels.get(rid)?.target : void 0;
|
|
422
855
|
const id = attrOf(text.slice(0, inner.openEnd), "ID");
|
|
423
856
|
if (target === void 0 || id === void 0) return void 0;
|
|
424
|
-
|
|
857
|
+
items.push({
|
|
425
858
|
id,
|
|
426
859
|
text,
|
|
427
|
-
path: resolveTarget(dirName(
|
|
860
|
+
path: resolveTarget(dirName(listPath), target),
|
|
428
861
|
rel: { start: relSpan.start, end: relSpan.end }
|
|
429
862
|
});
|
|
430
863
|
}
|
|
431
|
-
return { box,
|
|
864
|
+
return { box, items };
|
|
432
865
|
}
|
|
866
|
+
var withMark = (item) => item.text.slice(0, item.rel.start) + REL_MARK + item.text.slice(item.rel.end);
|
|
867
|
+
|
|
868
|
+
// visio/collab/snapshot-parts.ts
|
|
869
|
+
async function snapshotMasters(zip, layout, keys, derived) {
|
|
870
|
+
const masters = [];
|
|
871
|
+
let mastersOpen;
|
|
872
|
+
let mastersClose;
|
|
873
|
+
if (layout.mastersPath) {
|
|
874
|
+
const listXml = await zipText(zip, layout.mastersPath) ?? "";
|
|
875
|
+
const list = await readLocalItems(zip, layout.mastersPath, listXml, "Masters", "Master");
|
|
876
|
+
if (list) {
|
|
877
|
+
derived.add(layout.mastersPath).add(relsPathOf(layout.mastersPath));
|
|
878
|
+
mastersOpen = listXml.slice(0, list.box.openEnd);
|
|
879
|
+
mastersClose = listXml.slice(list.box.closeStart);
|
|
880
|
+
for (const item of list.items) {
|
|
881
|
+
const content = await zipText(zip, item.path);
|
|
882
|
+
if (content === void 0) continue;
|
|
883
|
+
derived.add(item.path).add(relsPathOf(item.path));
|
|
884
|
+
const key = keys.masterKey(item.id);
|
|
885
|
+
keys.masterPaths.set(key, item.path);
|
|
886
|
+
const rels = await zipText(zip, relsPathOf(item.path));
|
|
887
|
+
const { shell, shapes, connects } = splitContents(content, masterScope(key), keys);
|
|
888
|
+
masters.push({
|
|
889
|
+
key,
|
|
890
|
+
id: item.id,
|
|
891
|
+
xml: withMark(item),
|
|
892
|
+
path: item.path,
|
|
893
|
+
part: encoder.encode(shell),
|
|
894
|
+
...rels !== void 0 ? { rels } : {},
|
|
895
|
+
shapes,
|
|
896
|
+
connects
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return { masters, mastersOpen, mastersClose };
|
|
902
|
+
}
|
|
903
|
+
async function snapshotRest(zip, derived, limit) {
|
|
904
|
+
const parts = /* @__PURE__ */ new Map();
|
|
905
|
+
const media = [];
|
|
906
|
+
const typesXml = await zipText(zip, CONTENT_TYPES) ?? "";
|
|
907
|
+
const mediaPaths = /* @__PURE__ */ new Set();
|
|
908
|
+
let total = 0;
|
|
909
|
+
for (const path of Object.keys(zip.files)) {
|
|
910
|
+
const file = zip.files[path];
|
|
911
|
+
if (file.dir || derived.has(path) || isLocalOnlyPart(path)) continue;
|
|
912
|
+
const data = await file.async("uint8array");
|
|
913
|
+
total += data.length;
|
|
914
|
+
if (total > limit) throw new Error("The package parts exceed the shared size limit.");
|
|
915
|
+
const declared = isMediaPart(path) ? declaredType(typesXml, path) : void 0;
|
|
916
|
+
if (declared) {
|
|
917
|
+
mediaPaths.add(path);
|
|
918
|
+
media.push({
|
|
919
|
+
path,
|
|
920
|
+
hash: contentHash(data),
|
|
921
|
+
ct: declared.type,
|
|
922
|
+
d: declared.byDefault,
|
|
923
|
+
data
|
|
924
|
+
});
|
|
925
|
+
} else parts.set(path, data);
|
|
926
|
+
}
|
|
927
|
+
const types = parts.get(CONTENT_TYPES);
|
|
928
|
+
if (types)
|
|
929
|
+
parts.set(
|
|
930
|
+
CONTENT_TYPES,
|
|
931
|
+
encoder.encode(
|
|
932
|
+
stripOverrides(decoder.decode(types), [PAGE_CONTENT_TYPE, MASTER_CONTENT_TYPE], mediaPaths)
|
|
933
|
+
)
|
|
934
|
+
);
|
|
935
|
+
return { parts, media };
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// visio/collab/snapshot.ts
|
|
939
|
+
var DEFAULT_MAX_PART_BYTES = 48 * 1024 * 1024;
|
|
433
940
|
async function snapshotDrawing(bytes, keys, options = {}) {
|
|
434
941
|
const zip = await readZip(bytes);
|
|
435
942
|
const layout = await readLayout(zip);
|
|
436
943
|
if (!layout) throw new Error("The package has no Visio pages part.");
|
|
437
944
|
const pagesXml = await zipText(zip, layout.pagesPath) ?? "";
|
|
438
|
-
const local = await
|
|
945
|
+
const local = await readLocalItems(zip, layout.pagesPath, pagesXml, "Pages", "Page");
|
|
439
946
|
if (!local) throw new Error("The pages part cannot be split into pages.");
|
|
440
947
|
const derived = /* @__PURE__ */ new Set([layout.pagesPath, relsPathOf(layout.pagesPath)]);
|
|
441
|
-
const idToKey = new Map(local.
|
|
948
|
+
const idToKey = new Map(local.items.map((p) => [p.id, keys.pageKey(p.id)]));
|
|
442
949
|
const pages = [];
|
|
443
|
-
for (const page of local.
|
|
950
|
+
for (const page of local.items) {
|
|
444
951
|
const key = idToKey.get(page.id);
|
|
445
952
|
derived.add(page.path).add(relsPathOf(page.path));
|
|
446
953
|
const head = page.text.slice(0, scanContainer(page.text, "Page").openEnd);
|
|
447
954
|
const backId = attrOf(head, "BackPage");
|
|
448
|
-
const xml = page.text.slice(0, page.rel.start) + REL_MARK + page.text.slice(page.rel.end);
|
|
449
955
|
const content = await zipText(zip, page.path) ?? "";
|
|
450
956
|
const rels = await zipText(zip, relsPathOf(page.path));
|
|
451
|
-
const
|
|
452
|
-
const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
|
|
453
|
-
const owner = /* @__PURE__ */ new Map();
|
|
454
|
-
const shapes = [];
|
|
455
|
-
for (const text of shapesSplit.items) {
|
|
456
|
-
const ids = shapeIds(text);
|
|
457
|
-
const id = ids[0];
|
|
458
|
-
if (id === void 0) continue;
|
|
459
|
-
const shapeKey = keys.shapeKey(key, id);
|
|
460
|
-
for (const nested of ids) owner.set(nested, shapeKey);
|
|
461
|
-
shapes.push({ key: shapeKey, id, xml: text });
|
|
462
|
-
}
|
|
463
|
-
const connects = [];
|
|
464
|
-
for (const text of connectsSplit.items) {
|
|
465
|
-
const a = (name) => attrOf(text, name) ?? "";
|
|
466
|
-
const entry = {
|
|
467
|
-
fk: owner.get(a("FromSheet")) ?? "",
|
|
468
|
-
fi: a("FromSheet"),
|
|
469
|
-
tk: owner.get(a("ToSheet")) ?? "",
|
|
470
|
-
ti: a("ToSheet"),
|
|
471
|
-
fc: a("FromCell"),
|
|
472
|
-
tc: a("ToCell"),
|
|
473
|
-
fp: a("FromPart"),
|
|
474
|
-
tp: a("ToPart")
|
|
475
|
-
};
|
|
476
|
-
connects.push({
|
|
477
|
-
key: `${key}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
|
|
478
|
-
entry
|
|
479
|
-
});
|
|
480
|
-
}
|
|
957
|
+
const { shell, shapes, connects } = splitContents(content, key, keys);
|
|
481
958
|
keys.pagePaths.set(key, page.path);
|
|
482
959
|
pages.push({
|
|
483
960
|
key,
|
|
484
961
|
id: page.id,
|
|
485
962
|
...backId !== void 0 && idToKey.has(backId) ? { back: idToKey.get(backId) } : {},
|
|
486
|
-
xml,
|
|
487
|
-
shell
|
|
963
|
+
xml: withMark(page),
|
|
964
|
+
shell,
|
|
488
965
|
...rels !== void 0 ? { rels } : {},
|
|
489
966
|
path: page.path,
|
|
490
967
|
shapes,
|
|
491
968
|
connects
|
|
492
969
|
});
|
|
493
970
|
}
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
let data = await file.async("uint8array");
|
|
501
|
-
if (path === CONTENT_TYPES) data = encoder.encode(stripPageOverrides(decoder.decode(data)));
|
|
502
|
-
total += data.length;
|
|
503
|
-
if (total > limit) throw new Error("The package parts exceed the shared size limit.");
|
|
504
|
-
parts.set(path, data);
|
|
505
|
-
}
|
|
971
|
+
const { masters, mastersOpen, mastersClose } = await snapshotMasters(zip, layout, keys, derived);
|
|
972
|
+
const { parts, media } = await snapshotRest(
|
|
973
|
+
zip,
|
|
974
|
+
derived,
|
|
975
|
+
options.maxPartBytes ?? DEFAULT_MAX_PART_BYTES
|
|
976
|
+
);
|
|
506
977
|
return {
|
|
507
978
|
pagesPath: layout.pagesPath,
|
|
508
979
|
pagesOpen: pagesXml.slice(0, local.box.openEnd),
|
|
509
980
|
pagesClose: pagesXml.slice(local.box.closeStart),
|
|
510
981
|
pages,
|
|
982
|
+
...mastersOpen !== void 0 && mastersClose !== void 0 && layout.mastersPath ? { mastersPath: layout.mastersPath, mastersOpen, mastersClose } : {},
|
|
983
|
+
masters,
|
|
984
|
+
media,
|
|
511
985
|
parts
|
|
512
986
|
};
|
|
513
987
|
}
|
|
514
988
|
|
|
515
|
-
// visio/collab/
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
let i = 0;
|
|
528
|
-
while (i < order.length) {
|
|
529
|
-
const known = kept[i];
|
|
530
|
-
if (known !== void 0) {
|
|
531
|
-
result.set(order[i], known);
|
|
532
|
-
i++;
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
let end = i;
|
|
536
|
-
while (end < order.length && kept[end] === void 0) end++;
|
|
537
|
-
const lo = i > 0 ? kept[i - 1] : void 0;
|
|
538
|
-
const hi = end < order.length ? kept[end] : void 0;
|
|
539
|
-
const count = end - i;
|
|
540
|
-
for (let j = 0; j < count; j++) {
|
|
541
|
-
const key = order[i + j];
|
|
542
|
-
if (lo !== void 0 && hi !== void 0)
|
|
543
|
-
result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
|
|
544
|
-
else if (lo !== void 0) result.set(key, lo + j + 1);
|
|
545
|
-
else if (hi !== void 0) result.set(key, hi - count + j);
|
|
546
|
-
else result.set(key, j + 1);
|
|
989
|
+
// visio/collab/compose-lists.ts
|
|
990
|
+
var relTarget = (dir, path) => dir && path.startsWith(`${dir}/`) ? path.slice(dir.length + 1) : `/${path}`;
|
|
991
|
+
async function placeList(options) {
|
|
992
|
+
const { files, taken, localZip, items } = options;
|
|
993
|
+
const dir = dirName(options.listPath);
|
|
994
|
+
taken.add(options.listPath).add(relsPathOf(options.listPath));
|
|
995
|
+
const paths = /* @__PURE__ */ new Map();
|
|
996
|
+
for (const item of items) {
|
|
997
|
+
const known = options.known.get(item.key);
|
|
998
|
+
if (known && !taken.has(known) && localZip?.file(known)) {
|
|
999
|
+
paths.set(item.key, known);
|
|
1000
|
+
taken.add(known);
|
|
547
1001
|
}
|
|
548
|
-
i = end;
|
|
549
1002
|
}
|
|
550
|
-
|
|
1003
|
+
let counter = 0;
|
|
1004
|
+
for (const item of items) {
|
|
1005
|
+
if (paths.has(item.key)) continue;
|
|
1006
|
+
let path;
|
|
1007
|
+
do
|
|
1008
|
+
path = `${dir ? `${dir}/` : ""}${options.stem}${++counter}.xml`;
|
|
1009
|
+
while (taken.has(path) || localZip?.file(path));
|
|
1010
|
+
paths.set(item.key, path);
|
|
1011
|
+
taken.add(path);
|
|
1012
|
+
}
|
|
1013
|
+
const others = parseRelationships(
|
|
1014
|
+
localZip ? await zipText(localZip, relsPathOf(options.listPath)) : void 0
|
|
1015
|
+
).filter((r) => r.type !== options.relType);
|
|
1016
|
+
const usedIds = new Set(others.map((r) => r.id));
|
|
1017
|
+
let nextRel = 0;
|
|
1018
|
+
const rels = [];
|
|
1019
|
+
const elements = [];
|
|
1020
|
+
for (const item of items) {
|
|
1021
|
+
const path = paths.get(item.key);
|
|
1022
|
+
let id;
|
|
1023
|
+
do
|
|
1024
|
+
id = `rId${++nextRel}`;
|
|
1025
|
+
while (usedIds.has(id));
|
|
1026
|
+
usedIds.add(id);
|
|
1027
|
+
rels.push(
|
|
1028
|
+
`<Relationship Id="${id}" Type="${options.relType}" Target="${escapeAttr(relTarget(dir, path))}"/>`
|
|
1029
|
+
);
|
|
1030
|
+
const rel = `<Rel xmlns:r="${REL_NS}" r:id="${id}"/>`;
|
|
1031
|
+
elements.push(
|
|
1032
|
+
item.xml.includes(REL_MARK) ? item.xml.replace(REL_MARK, () => rel) : item.xml.slice(0, item.xml.lastIndexOf("</")) + rel + item.xml.slice(item.xml.lastIndexOf("</"))
|
|
1033
|
+
);
|
|
1034
|
+
files.set(path, item.part);
|
|
1035
|
+
if (item.rels !== void 0) files.set(relsPathOf(path), encoder.encode(item.rels));
|
|
1036
|
+
}
|
|
1037
|
+
files.set(options.listPath, encoder.encode(options.open + elements.join("") + options.close));
|
|
1038
|
+
files.set(
|
|
1039
|
+
relsPathOf(options.listPath),
|
|
1040
|
+
encoder.encode(
|
|
1041
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + rels.join("") + "</Relationships>"
|
|
1042
|
+
)
|
|
1043
|
+
);
|
|
1044
|
+
return paths;
|
|
551
1045
|
}
|
|
552
|
-
|
|
553
|
-
|
|
1046
|
+
new TextDecoder("utf-8", { fatal: true });
|
|
1047
|
+
var crcTable = Uint32Array.from({ length: 256 }, (_, value) => {
|
|
1048
|
+
for (let i = 0; i < 8; i++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
1049
|
+
return value >>> 0;
|
|
1050
|
+
});
|
|
1051
|
+
function crc32(bytes, crc = 4294967295) {
|
|
1052
|
+
for (const byte of bytes) crc = (crcTable[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
|
|
1053
|
+
return crc >>> 0;
|
|
554
1054
|
}
|
|
555
1055
|
|
|
556
|
-
// visio/collab/
|
|
557
|
-
var
|
|
558
|
-
var
|
|
559
|
-
var
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
if (setIfChanged(map, key, value)) writes++;
|
|
567
|
-
};
|
|
568
|
-
set(shared.meta, "v", SCHEMA_VERSION);
|
|
569
|
-
set(shared.meta, "pagesPath", snapshot.pagesPath);
|
|
570
|
-
set(shared.meta, "pagesOpen", snapshot.pagesOpen);
|
|
571
|
-
set(shared.meta, "pagesClose", snapshot.pagesClose);
|
|
572
|
-
const now = /* @__PURE__ */ new Map();
|
|
573
|
-
const changed = (id, content, room) => {
|
|
574
|
-
const base = keys.known.get(id);
|
|
575
|
-
return base === void 0 ? room !== content : base !== content;
|
|
576
|
-
};
|
|
577
|
-
const pagePos = assignPositions(
|
|
578
|
-
snapshot.pages.map((p) => p.key),
|
|
579
|
-
(key) => pageEntry(shared.pages.get(key))?.pos
|
|
580
|
-
);
|
|
581
|
-
for (const page of snapshot.pages) {
|
|
582
|
-
const room = pageEntry(shared.pages.get(page.key));
|
|
583
|
-
const content = pageContent(page);
|
|
584
|
-
now.set(pageId(page.key), content);
|
|
585
|
-
const own = changed(pageId(page.key), content, room && pageContent(room));
|
|
586
|
-
const source = own || !room ? page : room;
|
|
587
|
-
set(shared.pages, page.key, {
|
|
588
|
-
pos: pagePos.get(page.key),
|
|
589
|
-
id: source.id,
|
|
590
|
-
...source.back !== void 0 ? { back: source.back } : {},
|
|
591
|
-
xml: source.xml
|
|
592
|
-
});
|
|
593
|
-
const roomBody = bodyEntry(shared.bodies.get(page.key));
|
|
594
|
-
const bodyText = bodyContent(page);
|
|
595
|
-
now.set(bodyId(page.key), bodyText);
|
|
596
|
-
const ownBody = changed(bodyId(page.key), bodyText, roomBody && bodyContent(roomBody));
|
|
597
|
-
const body = ownBody || !roomBody ? page : roomBody;
|
|
598
|
-
set(shared.bodies, page.key, {
|
|
599
|
-
shell: body.shell,
|
|
600
|
-
...body.rels !== void 0 ? { rels: body.rels } : {}
|
|
601
|
-
});
|
|
602
|
-
const shapePos = assignPositions(
|
|
603
|
-
page.shapes.map((s) => s.key),
|
|
604
|
-
(key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
|
|
605
|
-
);
|
|
606
|
-
for (const shape of page.shapes) {
|
|
607
|
-
const id = shapeId(page.key, shape.key);
|
|
608
|
-
const roomShape = shapeEntry(shared.shapes.get(`${page.key}/${shape.key}`));
|
|
609
|
-
const text = canon(shape.xml);
|
|
610
|
-
now.set(id, text);
|
|
611
|
-
const xml = changed(id, text, roomShape && canon(roomShape.xml)) || !roomShape ? shape.xml : roomShape.xml;
|
|
612
|
-
set(shared.shapes, `${page.key}/${shape.key}`, { pos: shapePos.get(shape.key), xml });
|
|
613
|
-
}
|
|
614
|
-
for (const connect of page.connects) {
|
|
615
|
-
now.set(connectId(connect.key), "");
|
|
616
|
-
if (!keys.known.has(connectId(connect.key)) || !shared.connects.has(connect.key))
|
|
617
|
-
set(shared.connects, connect.key, connect.entry);
|
|
1056
|
+
// visio/collab/zip-store.ts
|
|
1057
|
+
var encoder2 = new TextEncoder();
|
|
1058
|
+
var DOS_TIME = 0;
|
|
1059
|
+
var DOS_DATE = 33;
|
|
1060
|
+
function writeStoredZip(files, crcs) {
|
|
1061
|
+
const prepared = files.map(([name, data]) => {
|
|
1062
|
+
let crc = crcs.get(data);
|
|
1063
|
+
if (crc === void 0) {
|
|
1064
|
+
crc = (crc32(data) ^ 4294967295) >>> 0;
|
|
1065
|
+
crcs.set(data, crc);
|
|
618
1066
|
}
|
|
1067
|
+
return { name: encoder2.encode(name), data, crc };
|
|
1068
|
+
});
|
|
1069
|
+
let local = 0;
|
|
1070
|
+
let central = 0;
|
|
1071
|
+
for (const f of prepared) {
|
|
1072
|
+
local += 30 + f.name.length + f.data.length;
|
|
1073
|
+
central += 46 + f.name.length;
|
|
619
1074
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
writes++;
|
|
641
|
-
}
|
|
1075
|
+
const out = new Uint8Array(local + central + 22);
|
|
1076
|
+
const view = new DataView(out.buffer);
|
|
1077
|
+
let at = 0;
|
|
1078
|
+
const offsets = [];
|
|
1079
|
+
for (const f of prepared) {
|
|
1080
|
+
offsets.push(at);
|
|
1081
|
+
view.setUint32(at, 67324752, true);
|
|
1082
|
+
view.setUint16(at + 4, 20, true);
|
|
1083
|
+
view.setUint16(at + 6, 2048, true);
|
|
1084
|
+
view.setUint16(at + 8, 0, true);
|
|
1085
|
+
view.setUint16(at + 10, DOS_TIME, true);
|
|
1086
|
+
view.setUint16(at + 12, DOS_DATE, true);
|
|
1087
|
+
view.setUint32(at + 14, f.crc, true);
|
|
1088
|
+
view.setUint32(at + 18, f.data.length, true);
|
|
1089
|
+
view.setUint32(at + 22, f.data.length, true);
|
|
1090
|
+
view.setUint16(at + 26, f.name.length, true);
|
|
1091
|
+
view.setUint16(at + 28, 0, true);
|
|
1092
|
+
out.set(f.name, at + 30);
|
|
1093
|
+
out.set(f.data, at + 30 + f.name.length);
|
|
1094
|
+
at += 30 + f.name.length + f.data.length;
|
|
642
1095
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
1096
|
+
const centralStart = at;
|
|
1097
|
+
prepared.forEach((f, i) => {
|
|
1098
|
+
view.setUint32(at, 33639248, true);
|
|
1099
|
+
view.setUint16(at + 4, 20, true);
|
|
1100
|
+
view.setUint16(at + 6, 20, true);
|
|
1101
|
+
view.setUint16(at + 8, 2048, true);
|
|
1102
|
+
view.setUint16(at + 10, 0, true);
|
|
1103
|
+
view.setUint16(at + 12, DOS_TIME, true);
|
|
1104
|
+
view.setUint16(at + 14, DOS_DATE, true);
|
|
1105
|
+
view.setUint32(at + 16, f.crc, true);
|
|
1106
|
+
view.setUint32(at + 20, f.data.length, true);
|
|
1107
|
+
view.setUint32(at + 24, f.data.length, true);
|
|
1108
|
+
view.setUint16(at + 28, f.name.length, true);
|
|
1109
|
+
view.setUint32(at + 42, offsets[i], true);
|
|
1110
|
+
out.set(f.name, at + 46);
|
|
1111
|
+
at += 46 + f.name.length;
|
|
1112
|
+
});
|
|
1113
|
+
view.setUint32(at, 101010256, true);
|
|
1114
|
+
view.setUint16(at + 8, prepared.length, true);
|
|
1115
|
+
view.setUint16(at + 10, prepared.length, true);
|
|
1116
|
+
view.setUint32(at + 12, at - centralStart, true);
|
|
1117
|
+
view.setUint32(at + 16, centralStart, true);
|
|
1118
|
+
return out;
|
|
657
1119
|
}
|
|
658
1120
|
|
|
659
1121
|
// visio/collab/compose.ts
|
|
@@ -669,32 +1131,51 @@ function connectXml(item) {
|
|
|
669
1131
|
];
|
|
670
1132
|
return `<Connect ${attrs.filter(([, v]) => v !== "").map(([k, v]) => `${k}="${escapeAttr(v)}"`).join(" ")}/>`;
|
|
671
1133
|
}
|
|
672
|
-
function
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return shell.replace(SHAPES_MARK, () => page.shapes.map((s) => s.xml).join("")).replace(CONNECTS_MARK, () => page.connects.map(connectXml).join(""));
|
|
681
|
-
}
|
|
682
|
-
function relTarget(pagesDir, path) {
|
|
683
|
-
return pagesDir && path.startsWith(`${pagesDir}/`) ? path.slice(pagesDir.length + 1) : `/${path}`;
|
|
1134
|
+
function contentsXml(shell, root, shapesXml, hasShapes, connects) {
|
|
1135
|
+
const outer = scanContainer(shell, root);
|
|
1136
|
+
if (hasShapes && !shell.includes(SHAPES_MARK) && outer && !outer.selfClosing)
|
|
1137
|
+
shell = shell.slice(0, outer.openEnd) + `<Shapes>${SHAPES_MARK}</Shapes>` + shell.slice(outer.openEnd);
|
|
1138
|
+
const outer2 = scanContainer(shell, root);
|
|
1139
|
+
if (connects.length && !shell.includes(CONNECTS_MARK) && outer2 && !outer2.selfClosing)
|
|
1140
|
+
shell = shell.slice(0, outer2.closeStart) + `<Connects>${CONNECTS_MARK}</Connects>` + shell.slice(outer2.closeStart);
|
|
1141
|
+
return shell.replace(SHAPES_MARK, () => shapesXml).replace(CONNECTS_MARK, () => connects.map(connectXml).join(""));
|
|
684
1142
|
}
|
|
1143
|
+
var pagePartXml = (page) => contentsXml(
|
|
1144
|
+
page.body.shell,
|
|
1145
|
+
"PageContents",
|
|
1146
|
+
page.shapesXml,
|
|
1147
|
+
page.shapes.length > 0,
|
|
1148
|
+
page.connects
|
|
1149
|
+
);
|
|
1150
|
+
var masterPartXml = (master) => contentsXml(
|
|
1151
|
+
decoder.decode(fromBase64(master.part)),
|
|
1152
|
+
"MasterContents",
|
|
1153
|
+
master.shapesXml,
|
|
1154
|
+
master.shapes.length > 0,
|
|
1155
|
+
master.connects
|
|
1156
|
+
);
|
|
685
1157
|
async function composeDrawing(drawing, local, keys, options = {}) {
|
|
686
1158
|
const localZip = local ? await readZip(local) : void 0;
|
|
687
1159
|
const files = /* @__PURE__ */ new Map();
|
|
688
1160
|
const prints = /* @__PURE__ */ new Map();
|
|
689
1161
|
let total = 0;
|
|
690
1162
|
const limit = options.maxPartBytes ?? 48 * 1024 * 1024;
|
|
691
|
-
|
|
692
|
-
|
|
1163
|
+
const cache = keys.cache.parts;
|
|
1164
|
+
const decode = (path, b64) => {
|
|
1165
|
+
const hit = cache.get(path);
|
|
1166
|
+
const data = hit && hit.b64 === b64 ? hit.data : fromBase64(b64);
|
|
1167
|
+
if (!hit || hit.b64 !== b64) cache.set(path, { b64, data });
|
|
693
1168
|
total += data.length;
|
|
694
1169
|
if (total > limit) throw new Error("The shared parts exceed the size limit.");
|
|
1170
|
+
return data;
|
|
1171
|
+
};
|
|
1172
|
+
for (const [path, b64] of drawing.parts) {
|
|
1173
|
+
const data = decode(path, b64);
|
|
695
1174
|
files.set(path, data);
|
|
696
1175
|
prints.set(path, fingerprint(data));
|
|
697
1176
|
}
|
|
1177
|
+
for (const path of [...cache.keys()])
|
|
1178
|
+
if (!drawing.parts.has(path) && !path.startsWith("media:")) cache.delete(path);
|
|
698
1179
|
if (localZip)
|
|
699
1180
|
for (const path of Object.keys(localZip.files)) {
|
|
700
1181
|
const file = localZip.files[path];
|
|
@@ -702,6 +1183,10 @@ async function composeDrawing(drawing, local, keys, options = {}) {
|
|
|
702
1183
|
files.set(path, await file.async("uint8array"));
|
|
703
1184
|
}
|
|
704
1185
|
let contentTypes = files.get(CONTENT_TYPES) !== void 0 ? decoder.decode(files.get(CONTENT_TYPES)) : (localZip && await zipText(localZip, CONTENT_TYPES)) ?? DEFAULT_CONTENT_TYPES;
|
|
1186
|
+
for (const item of drawing.media) {
|
|
1187
|
+
files.set(item.path, decode(`media:${item.path}`, item.data));
|
|
1188
|
+
contentTypes = ensureType(contentTypes, item.path, item.declared);
|
|
1189
|
+
}
|
|
705
1190
|
for (const [path, data] of [...files]) {
|
|
706
1191
|
if (!path.endsWith(".rels") || typeof data === "string") continue;
|
|
707
1192
|
const source = path.replace(/(^|\/)_rels\/([^/]+)\.rels$/, "$1$2");
|
|
@@ -720,91 +1205,119 @@ async function composeDrawing(drawing, local, keys, options = {}) {
|
|
|
720
1205
|
});
|
|
721
1206
|
if (next !== text) files.set(path, encoder.encode(next));
|
|
722
1207
|
}
|
|
723
|
-
const
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
localZip
|
|
749
|
-
)
|
|
750
|
-
|
|
751
|
-
let
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
1208
|
+
const taken = new Set(files.keys());
|
|
1209
|
+
const pageCache = keys.cache.pageParts;
|
|
1210
|
+
const pageItems = drawing.pages.map((page) => {
|
|
1211
|
+
const hit = pageCache.get(page.key);
|
|
1212
|
+
const bytes2 = hit && hit.sig === page.signature ? hit.bytes : encoder.encode(pagePartXml(page));
|
|
1213
|
+
pageCache.set(page.key, { sig: page.signature, bytes: bytes2 });
|
|
1214
|
+
return {
|
|
1215
|
+
key: page.key,
|
|
1216
|
+
xml: page.xml,
|
|
1217
|
+
part: bytes2,
|
|
1218
|
+
...page.body.rels !== void 0 ? { rels: page.body.rels } : {}
|
|
1219
|
+
};
|
|
1220
|
+
});
|
|
1221
|
+
for (const key of [...pageCache.keys()])
|
|
1222
|
+
if (!drawing.pages.some((p) => p.key === key)) pageCache.delete(key);
|
|
1223
|
+
const pagePaths = await placeList({
|
|
1224
|
+
listPath: drawing.pagesPath,
|
|
1225
|
+
open: drawing.pagesOpen,
|
|
1226
|
+
close: drawing.pagesClose,
|
|
1227
|
+
relType: PAGE_TYPE,
|
|
1228
|
+
stem: "page",
|
|
1229
|
+
items: pageItems,
|
|
1230
|
+
known: keys.pagePaths,
|
|
1231
|
+
files,
|
|
1232
|
+
taken,
|
|
1233
|
+
localZip
|
|
1234
|
+
});
|
|
1235
|
+
contentTypes = withPageOverrides(contentTypes, [...pagePaths.values()]);
|
|
1236
|
+
let masterPaths = /* @__PURE__ */ new Map();
|
|
1237
|
+
if (drawing.mastersPath !== void 0) {
|
|
1238
|
+
masterPaths = await placeList({
|
|
1239
|
+
listPath: drawing.mastersPath,
|
|
1240
|
+
open: drawing.mastersOpen ?? "<Masters>",
|
|
1241
|
+
close: drawing.mastersClose ?? "</Masters>",
|
|
1242
|
+
relType: MASTER_TYPE,
|
|
1243
|
+
stem: "master",
|
|
1244
|
+
items: drawing.masters.map((m) => ({
|
|
1245
|
+
key: m.key,
|
|
1246
|
+
xml: m.xml,
|
|
1247
|
+
part: encoder.encode(masterPartXml(m)),
|
|
1248
|
+
...m.rels !== void 0 ? { rels: m.rels } : {}
|
|
1249
|
+
})),
|
|
1250
|
+
known: keys.masterPaths,
|
|
1251
|
+
files,
|
|
1252
|
+
taken,
|
|
1253
|
+
localZip
|
|
1254
|
+
});
|
|
1255
|
+
contentTypes = withOverrides(contentTypes, MASTER_CONTENT_TYPE, [...masterPaths.values()]);
|
|
770
1256
|
}
|
|
771
|
-
files.set(
|
|
772
|
-
drawing.pagesPath,
|
|
773
|
-
encoder.encode(drawing.pagesOpen + pageXml.join("") + drawing.pagesClose)
|
|
774
|
-
);
|
|
775
|
-
files.set(
|
|
776
|
-
relsPathOf(drawing.pagesPath),
|
|
777
|
-
encoder.encode(
|
|
778
|
-
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + pageRels.join("") + "</Relationships>"
|
|
779
|
-
)
|
|
780
|
-
);
|
|
781
|
-
files.set(CONTENT_TYPES, encoder.encode(withPageOverrides(contentTypes, [...paths.values()])));
|
|
782
|
-
const zip = new JSZip();
|
|
1257
|
+
files.set(CONTENT_TYPES, encoder.encode(contentTypes));
|
|
783
1258
|
const names = [...files.keys()].sort(
|
|
784
1259
|
(a, b) => a === CONTENT_TYPES ? -1 : b === CONTENT_TYPES ? 1 : 0
|
|
785
1260
|
);
|
|
786
|
-
|
|
787
|
-
|
|
1261
|
+
const bytes = writeStoredZip(
|
|
1262
|
+
names.map((name) => {
|
|
1263
|
+
const data = files.get(name);
|
|
1264
|
+
return [name, typeof data === "string" ? encoder.encode(data) : data];
|
|
1265
|
+
}),
|
|
1266
|
+
keys.cache.crcs
|
|
1267
|
+
);
|
|
788
1268
|
const commit = () => {
|
|
789
1269
|
const pageIds = /* @__PURE__ */ new Map();
|
|
790
|
-
const
|
|
1270
|
+
const shapeIds = /* @__PURE__ */ new Map();
|
|
1271
|
+
const masterIds = /* @__PURE__ */ new Map();
|
|
791
1272
|
const known = /* @__PURE__ */ new Map();
|
|
1273
|
+
const recordShapes = (scope, shapes, connects) => {
|
|
1274
|
+
shapeIds.set(scope, new Map(shapes.map((s) => [s.id, s.key])));
|
|
1275
|
+
for (const shape of shapes) {
|
|
1276
|
+
known.set(shapeId(scope, shape.key), shellContent(shape));
|
|
1277
|
+
for (const [path, entry] of shape.entries)
|
|
1278
|
+
known.set(cellId(scope, shape.key, path), entryContent(entry));
|
|
1279
|
+
}
|
|
1280
|
+
for (const connect of connects) known.set(connectId(connect.key), "");
|
|
1281
|
+
};
|
|
792
1282
|
keys.pagePaths.clear();
|
|
1283
|
+
keys.masterPaths.clear();
|
|
1284
|
+
keys.mediaKeys.clear();
|
|
793
1285
|
for (const page of drawing.pages) {
|
|
794
1286
|
pageIds.set(page.id, page.key);
|
|
795
|
-
keys.pagePaths.set(page.key,
|
|
1287
|
+
keys.pagePaths.set(page.key, pagePaths.get(page.key));
|
|
796
1288
|
known.set(pageId(page.key), pageContent(page));
|
|
797
1289
|
known.set(bodyId(page.key), bodyContent(page.body));
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1290
|
+
recordShapes(page.key, page.shapes, page.connects);
|
|
1291
|
+
}
|
|
1292
|
+
for (const master of drawing.masters) {
|
|
1293
|
+
masterIds.set(master.id, master.key);
|
|
1294
|
+
recordShapes(masterScope(master.key), master.shapes, master.connects);
|
|
1295
|
+
const path = masterPaths.get(master.key);
|
|
1296
|
+
if (path) keys.masterPaths.set(master.key, path);
|
|
1297
|
+
known.set(
|
|
1298
|
+
masterId(master.key),
|
|
1299
|
+
masterContent({ ...master, print: fingerprint(fromBase64(master.part)) })
|
|
1300
|
+
);
|
|
801
1301
|
}
|
|
802
|
-
|
|
1302
|
+
for (const item of drawing.media) {
|
|
1303
|
+
known.set(mediaId(item.key), "");
|
|
1304
|
+
keys.mediaKeys.set(item.path, item.key);
|
|
1305
|
+
}
|
|
1306
|
+
keys.reset(pageIds, shapeIds, masterIds);
|
|
803
1307
|
keys.known = known;
|
|
804
1308
|
keys.partPrints.clear();
|
|
805
1309
|
for (const [path, print] of prints) keys.partPrints.set(path, print);
|
|
806
1310
|
};
|
|
807
|
-
return { bytes, commit };
|
|
1311
|
+
return { bytes, signature: drawing.signature, commit };
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// visio/collab/fixups.ts
|
|
1315
|
+
function applyFixups(shared, fixups) {
|
|
1316
|
+
let changed = 0;
|
|
1317
|
+
for (const fixup of fixups) {
|
|
1318
|
+
if (setIfChanged(shared.renum, fixup.key, fixup.value)) changed++;
|
|
1319
|
+
}
|
|
1320
|
+
return changed;
|
|
808
1321
|
}
|
|
809
1322
|
|
|
810
1323
|
// visio/collab/keys.ts
|
|
@@ -818,15 +1331,36 @@ var DrawingKeys = class {
|
|
|
818
1331
|
seeding = false;
|
|
819
1332
|
#pages = /* @__PURE__ */ new Map();
|
|
820
1333
|
#shapes = /* @__PURE__ */ new Map();
|
|
1334
|
+
#masters = /* @__PURE__ */ new Map();
|
|
821
1335
|
/** Content of each entry this peer last wrote or applied, to tell a local edit or deletion from a change it has not applied yet. */
|
|
822
1336
|
known = /* @__PURE__ */ new Map();
|
|
823
1337
|
/** Fingerprints of the parts this peer last wrote or applied. */
|
|
824
1338
|
partPrints = /* @__PURE__ */ new Map();
|
|
825
1339
|
/** The part path of each page key in the local package. */
|
|
826
1340
|
pagePaths = /* @__PURE__ */ new Map();
|
|
1341
|
+
/** The part path of each master key in the local package. */
|
|
1342
|
+
masterPaths = /* @__PURE__ */ new Map();
|
|
1343
|
+
/** The room key of each media path in the local package. */
|
|
1344
|
+
mediaKeys = /* @__PURE__ */ new Map();
|
|
1345
|
+
/** Serialised page parts and decoded shared parts of the last rebuild, to skip unchanged work. */
|
|
1346
|
+
cache = {
|
|
1347
|
+
pageParts: /* @__PURE__ */ new Map(),
|
|
1348
|
+
parts: /* @__PURE__ */ new Map(),
|
|
1349
|
+
/** CRC-32 of the bytes of each stored part, by identity (see zip-store.ts). */
|
|
1350
|
+
crcs: /* @__PURE__ */ new WeakMap()
|
|
1351
|
+
};
|
|
1352
|
+
/**
|
|
1353
|
+
* What was last applied to the editor: the drawing signature, the editor version it produced,
|
|
1354
|
+
* the signature of everything but page content and the content signature of each page.
|
|
1355
|
+
*/
|
|
1356
|
+
applied;
|
|
827
1357
|
mint() {
|
|
828
1358
|
return `${this.tag}.${(++this.#counter).toString(36)}`;
|
|
829
1359
|
}
|
|
1360
|
+
/** A fresh id for one write batch: entries written together share it. */
|
|
1361
|
+
batch() {
|
|
1362
|
+
return this.mint();
|
|
1363
|
+
}
|
|
830
1364
|
pageKey(id) {
|
|
831
1365
|
let key = this.#pages.get(id);
|
|
832
1366
|
if (key === void 0) {
|
|
@@ -845,6 +1379,14 @@ var DrawingKeys = class {
|
|
|
845
1379
|
}
|
|
846
1380
|
return key;
|
|
847
1381
|
}
|
|
1382
|
+
masterKey(id) {
|
|
1383
|
+
let key = this.#masters.get(id);
|
|
1384
|
+
if (key === void 0) {
|
|
1385
|
+
key = this.seeding ? `s${id}` : this.mint();
|
|
1386
|
+
this.#masters.set(id, key);
|
|
1387
|
+
}
|
|
1388
|
+
return key;
|
|
1389
|
+
}
|
|
848
1390
|
findPage(id) {
|
|
849
1391
|
return this.#pages.get(id);
|
|
850
1392
|
}
|
|
@@ -858,38 +1400,352 @@ var DrawingKeys = class {
|
|
|
858
1400
|
for (const [id, k] of map) if (k === key) map.delete(id);
|
|
859
1401
|
}
|
|
860
1402
|
}
|
|
1403
|
+
forgetMaster(key) {
|
|
1404
|
+
for (const [id, k] of this.#masters) if (k === key) this.#masters.delete(id);
|
|
1405
|
+
this.#shapes.delete(masterScope(key));
|
|
1406
|
+
this.masterPaths.delete(key);
|
|
1407
|
+
}
|
|
861
1408
|
/** Replaces the id-to-key tables with those of a freshly composed package. */
|
|
862
|
-
reset(pages, shapes) {
|
|
1409
|
+
reset(pages, shapes, masters = /* @__PURE__ */ new Map()) {
|
|
863
1410
|
this.#pages.clear();
|
|
864
1411
|
this.#shapes.clear();
|
|
1412
|
+
this.#masters.clear();
|
|
865
1413
|
for (const [id, key] of pages) this.#pages.set(id, key);
|
|
866
1414
|
for (const [page, map] of shapes) this.#shapes.set(page, new Map(map));
|
|
1415
|
+
for (const [id, key] of masters) this.#masters.set(id, key);
|
|
867
1416
|
}
|
|
868
1417
|
};
|
|
869
1418
|
|
|
870
|
-
// visio/collab/
|
|
1419
|
+
// visio/collab/order.ts
|
|
1420
|
+
function assignPositions(order, current) {
|
|
1421
|
+
const result = /* @__PURE__ */ new Map();
|
|
1422
|
+
const kept = [];
|
|
1423
|
+
let last = -Infinity;
|
|
1424
|
+
for (const key of order) {
|
|
1425
|
+
const pos = current(key);
|
|
1426
|
+
if (pos !== void 0 && pos > last) {
|
|
1427
|
+
kept.push(pos);
|
|
1428
|
+
last = pos;
|
|
1429
|
+
} else kept.push(void 0);
|
|
1430
|
+
}
|
|
1431
|
+
let i = 0;
|
|
1432
|
+
while (i < order.length) {
|
|
1433
|
+
const known = kept[i];
|
|
1434
|
+
if (known !== void 0) {
|
|
1435
|
+
result.set(order[i], known);
|
|
1436
|
+
i++;
|
|
1437
|
+
continue;
|
|
1438
|
+
}
|
|
1439
|
+
let end = i;
|
|
1440
|
+
while (end < order.length && kept[end] === void 0) end++;
|
|
1441
|
+
const lo = i > 0 ? kept[i - 1] : void 0;
|
|
1442
|
+
const hi = end < order.length ? kept[end] : void 0;
|
|
1443
|
+
const count = end - i;
|
|
1444
|
+
for (let j = 0; j < count; j++) {
|
|
1445
|
+
const key = order[i + j];
|
|
1446
|
+
if (lo !== void 0 && hi !== void 0)
|
|
1447
|
+
result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
|
|
1448
|
+
else if (lo !== void 0) result.set(key, lo + j + 1);
|
|
1449
|
+
else if (hi !== void 0) result.set(key, hi - count + j);
|
|
1450
|
+
else result.set(key, j + 1);
|
|
1451
|
+
}
|
|
1452
|
+
i = end;
|
|
1453
|
+
}
|
|
1454
|
+
return result;
|
|
1455
|
+
}
|
|
1456
|
+
function byPosition(items) {
|
|
1457
|
+
return items.sort((a, b) => a.pos - b.pos || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// visio/collab/read-ids.ts
|
|
871
1461
|
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
872
1462
|
var numeric = (id) => /^\d+$/.test(id) ? Number(id) : 0;
|
|
1463
|
+
function assignIds(items) {
|
|
1464
|
+
const effective = (item) => item.fixed ?? item.id;
|
|
1465
|
+
let max = Math.max(0, ...items.map((item) => numeric(effective(item))));
|
|
1466
|
+
const order = [...items].sort(
|
|
1467
|
+
(a, b) => Number(b.fixed !== void 0) - Number(a.fixed !== void 0) || compare(a.key, b.key)
|
|
1468
|
+
);
|
|
1469
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1470
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
1471
|
+
const holder = /* @__PURE__ */ new Map();
|
|
1472
|
+
const claims = /* @__PURE__ */ new Set();
|
|
1473
|
+
for (const item of order) {
|
|
1474
|
+
let id = effective(item);
|
|
1475
|
+
const taken = holder.get(id);
|
|
1476
|
+
if (taken) {
|
|
1477
|
+
if (taken.fixed === void 0) claims.add(taken.key);
|
|
1478
|
+
id = String(++max);
|
|
1479
|
+
fresh.set(item.key, { from: item.id, to: id });
|
|
1480
|
+
}
|
|
1481
|
+
holder.set(id, item);
|
|
1482
|
+
ids.set(item.key, id);
|
|
1483
|
+
}
|
|
1484
|
+
return { ids, fresh, claims };
|
|
1485
|
+
}
|
|
1486
|
+
var fixedId = (renum, key, id) => {
|
|
1487
|
+
const pair = renum.get(key)?.i;
|
|
1488
|
+
return pair && pair[0] === id ? pair[1] : void 0;
|
|
1489
|
+
};
|
|
1490
|
+
function readRenum(shared) {
|
|
1491
|
+
const out = /* @__PURE__ */ new Map();
|
|
1492
|
+
for (const [key, value] of shared.renum) {
|
|
1493
|
+
const entry = renumEntry(value);
|
|
1494
|
+
if (entry) out.set(key, entry);
|
|
1495
|
+
}
|
|
1496
|
+
return out;
|
|
1497
|
+
}
|
|
1498
|
+
function renumRecord(renum, recordKey, item, change, claimed) {
|
|
1499
|
+
if (change) return { ...renum.get(recordKey), i: [change.from, change.to] };
|
|
1500
|
+
if (claimed) return { ...renum.get(recordKey), i: [item.id, item.id] };
|
|
1501
|
+
return void 0;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// visio/collab/read-util.ts
|
|
1505
|
+
function hashTexts(texts) {
|
|
1506
|
+
let a = 2166136261;
|
|
1507
|
+
let b = 16777619 ^ 2654435769;
|
|
1508
|
+
for (const text of texts) {
|
|
1509
|
+
for (let i = 0; i < text.length; i++) {
|
|
1510
|
+
const c = text.charCodeAt(i);
|
|
1511
|
+
a = Math.imul(a ^ c, 16777619);
|
|
1512
|
+
b = Math.imul(b + c, 2246822507) ^ b >>> 13;
|
|
1513
|
+
}
|
|
1514
|
+
a = Math.imul(a ^ 255, 16777619);
|
|
1515
|
+
b = Math.imul(b ^ 255, 3266489909);
|
|
1516
|
+
}
|
|
1517
|
+
return `${(a >>> 0).toString(16)}${(b >>> 0).toString(16)}`;
|
|
1518
|
+
}
|
|
1519
|
+
var split = (key, depth) => {
|
|
1520
|
+
const out = [];
|
|
1521
|
+
let from = 0;
|
|
1522
|
+
for (let i = 0; i < depth; i++) {
|
|
1523
|
+
const slash = key.indexOf("/", from);
|
|
1524
|
+
if (slash < 0) return void 0;
|
|
1525
|
+
out.push(key.slice(from, slash));
|
|
1526
|
+
from = slash + 1;
|
|
1527
|
+
}
|
|
1528
|
+
out.push(key.slice(from));
|
|
1529
|
+
return out;
|
|
1530
|
+
};
|
|
1531
|
+
var connectSignature = (connects) => connects.flatMap((c) => [c.from, c.to, c.entry.fc, c.entry.tc, c.entry.fp, c.entry.tp]);
|
|
1532
|
+
function resolveConnects(list, shapes) {
|
|
1533
|
+
const byKey = new Map(shapes.map((s) => [s.key, s]));
|
|
1534
|
+
const out = [];
|
|
1535
|
+
for (const item of [...list ?? []].sort((a, b) => compare(a.key, b.key))) {
|
|
1536
|
+
const { entry } = item;
|
|
1537
|
+
const from = entry.fk ? byKey.get(entry.fk) : void 0;
|
|
1538
|
+
const to = entry.tk ? byKey.get(entry.tk) : void 0;
|
|
1539
|
+
if (entry.fk && !from || entry.tk && !to) continue;
|
|
1540
|
+
out.push({ key: item.key, entry, from: from?.id ?? entry.fi, to: to?.id ?? entry.ti });
|
|
1541
|
+
}
|
|
1542
|
+
return out;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// visio/collab/read-shapes.ts
|
|
873
1546
|
function setAttr(open, name, value) {
|
|
874
1547
|
return open.replace(
|
|
875
1548
|
new RegExp(String.raw`(\s${name}\s*=\s*)(?:"[^"]*"|'[^']*')`),
|
|
876
1549
|
(_m, head) => `${head}"${value}"`
|
|
877
1550
|
);
|
|
878
1551
|
}
|
|
879
|
-
function
|
|
880
|
-
if (!remap.size) return xml;
|
|
881
|
-
return xml.replace(
|
|
882
|
-
|
|
883
|
-
(tag) => tag.replace(/(\bID\s*=\s*)(["'])(\d+)\2/, (m, head, q, id) => {
|
|
1552
|
+
function renumberFormulas(xml, remap) {
|
|
1553
|
+
if (!remap.size || !xml.includes("Sheet.")) return xml;
|
|
1554
|
+
return xml.replace(/(\sF\s*=\s*)("[^"]*"|'[^']*')/g, (_m, head, value) => {
|
|
1555
|
+
const body = value.slice(1, -1).replace(/Sheet\.(\d+)(?!\d)/g, (m, id) => {
|
|
884
1556
|
const next = remap.get(id);
|
|
885
|
-
return next === void 0 ? m :
|
|
1557
|
+
return next === void 0 ? m : `Sheet.${next}`;
|
|
1558
|
+
});
|
|
1559
|
+
return `${head}${value[0]}${body}${value[0]}`;
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
function referenced(r, finalId) {
|
|
1563
|
+
const out = /* @__PURE__ */ new Map();
|
|
1564
|
+
for (let i = 0; i + 1 < r.length; i += 2) {
|
|
1565
|
+
const next = finalId.get(r[i + 1]);
|
|
1566
|
+
if (next !== void 0) out.set(r[i], next);
|
|
1567
|
+
}
|
|
1568
|
+
return out;
|
|
1569
|
+
}
|
|
1570
|
+
function resolveShapes(input) {
|
|
1571
|
+
const raw = /* @__PURE__ */ new Map();
|
|
1572
|
+
for (const [key, entry] of input.shapes) {
|
|
1573
|
+
const id = attrOf(entry.open, "ID");
|
|
1574
|
+
if (id !== void 0) raw.set(key, { entry, id });
|
|
1575
|
+
}
|
|
1576
|
+
const state = /* @__PURE__ */ new Map();
|
|
1577
|
+
const valid = (key, seen = /* @__PURE__ */ new Set()) => {
|
|
1578
|
+
const known = state.get(key);
|
|
1579
|
+
if (known !== void 0) return known;
|
|
1580
|
+
const item = raw.get(key);
|
|
1581
|
+
const parent = item?.entry.parent;
|
|
1582
|
+
let ok = !!item;
|
|
1583
|
+
if (ok && parent !== void 0) ok = !seen.has(key) && valid(parent, seen.add(key));
|
|
1584
|
+
state.set(key, ok);
|
|
1585
|
+
return ok;
|
|
1586
|
+
};
|
|
1587
|
+
const live = [...raw.keys()].filter((k) => valid(k)).sort(compare);
|
|
1588
|
+
const {
|
|
1589
|
+
ids: finalId,
|
|
1590
|
+
fresh: renumbered,
|
|
1591
|
+
claims
|
|
1592
|
+
} = assignIds(
|
|
1593
|
+
live.map((key) => {
|
|
1594
|
+
const { id } = raw.get(key);
|
|
1595
|
+
return { key, id, fixed: fixedId(input.renum, key, id) };
|
|
886
1596
|
})
|
|
887
|
-
)
|
|
888
|
-
|
|
889
|
-
|
|
1597
|
+
);
|
|
1598
|
+
const children = /* @__PURE__ */ new Map();
|
|
1599
|
+
for (const key of live) {
|
|
1600
|
+
const parent = raw.get(key).entry.parent ?? "";
|
|
1601
|
+
children.set(parent, [...children.get(parent) ?? [], key]);
|
|
1602
|
+
}
|
|
1603
|
+
const sortSiblings = (keys) => keys.sort((a, b) => raw.get(a).entry.pos - raw.get(b).entry.pos || compare(a, b));
|
|
1604
|
+
const shapes = [];
|
|
1605
|
+
const fixups = [];
|
|
1606
|
+
const render = (key) => {
|
|
1607
|
+
const { entry } = raw.get(key);
|
|
1608
|
+
const id = finalId.get(key);
|
|
1609
|
+
let open = setAttr(entry.open, "ID", id);
|
|
1610
|
+
const idRecord = renumRecord(
|
|
1611
|
+
input.renum,
|
|
1612
|
+
`${input.scope}/${key}`,
|
|
1613
|
+
{ id: raw.get(key).id },
|
|
1614
|
+
renumbered.get(key),
|
|
1615
|
+
claims.has(key)
|
|
1616
|
+
);
|
|
1617
|
+
const record = { ...idRecord ?? input.renum.get(key) };
|
|
1618
|
+
let dirty = idRecord !== void 0;
|
|
1619
|
+
const master = attrOf(open, "Master");
|
|
1620
|
+
const persisted = record.m && record.m[0] === master ? record.m[1] : void 0;
|
|
1621
|
+
const batched = master !== void 0 ? input.masterRemap.get(entry.b ?? "")?.get(master) : void 0;
|
|
1622
|
+
const next = persisted ?? batched;
|
|
1623
|
+
if (next !== void 0) open = setAttr(open, "Master", next);
|
|
1624
|
+
if (persisted === void 0 && batched !== void 0) {
|
|
1625
|
+
record.m = [master, batched];
|
|
1626
|
+
dirty = true;
|
|
1627
|
+
}
|
|
1628
|
+
if (dirty) fixups.push({ map: "renum", key: `${input.scope}/${key}`, value: record });
|
|
1629
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1630
|
+
for (const [path, piece] of input.cells.get(key) ?? []) {
|
|
1631
|
+
const leaf = piece.xml !== void 0 && piece.r !== void 0;
|
|
1632
|
+
const xml2 = leaf ? renumberFormulas(piece.xml, referenced(piece.r, finalId)) : void 0;
|
|
1633
|
+
entries.set(path, xml2 !== void 0 && xml2 !== piece.xml ? { ...piece, xml: xml2 } : piece);
|
|
1634
|
+
}
|
|
1635
|
+
shapes.push({
|
|
1636
|
+
key,
|
|
1637
|
+
id,
|
|
1638
|
+
...entry.parent !== void 0 ? { parent: entry.parent } : {},
|
|
1639
|
+
open,
|
|
1640
|
+
entries
|
|
1641
|
+
});
|
|
1642
|
+
const inner = sortSiblings(children.get(key) ?? []).map(render).join("");
|
|
1643
|
+
return buildShape(open, entries, inner ? `<Shapes>${inner}</Shapes>` : "");
|
|
1644
|
+
};
|
|
1645
|
+
const xml = sortSiblings(children.get("") ?? []).map(render).join("");
|
|
1646
|
+
return { shapes, xml, fixups };
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
// visio/collab/read-parts.ts
|
|
1650
|
+
var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
1651
|
+
function resolveMasters(shared, renum) {
|
|
1652
|
+
const alive = [];
|
|
1653
|
+
for (const [key, value] of shared.masters) {
|
|
1654
|
+
const entry = masterEntry(value);
|
|
1655
|
+
if (entry) alive.push({ key, entry });
|
|
1656
|
+
}
|
|
1657
|
+
const { ids, fresh, claims } = assignIds(
|
|
1658
|
+
alive.map(({ key, entry }) => ({
|
|
1659
|
+
key,
|
|
1660
|
+
id: entry.id,
|
|
1661
|
+
fixed: fixedId(renum, masterScope(key), entry.id)
|
|
1662
|
+
}))
|
|
1663
|
+
);
|
|
1664
|
+
const remap = /* @__PURE__ */ new Map();
|
|
1665
|
+
const fixups = [];
|
|
1666
|
+
for (const [key, change] of [...fresh].sort((a, b) => compare2(a[0], b[0]))) {
|
|
1667
|
+
const b = alive.find((m) => m.key === key).entry.b;
|
|
1668
|
+
if (b !== void 0) {
|
|
1669
|
+
const map = remap.get(b) ?? /* @__PURE__ */ new Map();
|
|
1670
|
+
map.set(change.from, change.to);
|
|
1671
|
+
remap.set(b, map);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
for (const { key, entry } of [...alive].sort((a, b) => compare2(a.key, b.key))) {
|
|
1675
|
+
const value = renumRecord(renum, masterScope(key), entry, fresh.get(key), claims.has(key));
|
|
1676
|
+
if (value) fixups.push({ map: "renum", key: masterScope(key), value });
|
|
1677
|
+
}
|
|
1678
|
+
alive.sort((a, b) => a.entry.pos - b.entry.pos || compare2(a.key, b.key));
|
|
1679
|
+
return {
|
|
1680
|
+
masters: alive.map(({ key, entry }) => {
|
|
1681
|
+
const id = ids.get(key);
|
|
1682
|
+
const open = /^<[^>]*>/.exec(entry.xml)?.[0];
|
|
1683
|
+
return {
|
|
1684
|
+
key,
|
|
1685
|
+
id,
|
|
1686
|
+
xml: open ? setAttr(open, "ID", id) + entry.xml.slice(open.length) : entry.xml,
|
|
1687
|
+
part: entry.part,
|
|
1688
|
+
...entry.rels !== void 0 ? { rels: entry.rels } : {}
|
|
1689
|
+
};
|
|
1690
|
+
}),
|
|
1691
|
+
remap,
|
|
1692
|
+
fixups
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
function resolveMedia(shared) {
|
|
1696
|
+
const items = [...shared.media].flatMap(([key, value]) => {
|
|
1697
|
+
const entry = mediaEntry(value);
|
|
1698
|
+
const data = entry ? str(shared.blobs.get(entry.hash)) : void 0;
|
|
1699
|
+
return entry && data !== void 0 ? [{ key, entry, data }] : [];
|
|
1700
|
+
}).sort((a, b) => compare2(a.key, b.key));
|
|
1701
|
+
const taken = /* @__PURE__ */ new Set();
|
|
1702
|
+
const first = /* @__PURE__ */ new Map();
|
|
1703
|
+
for (const item of items) if (!first.has(item.entry.path)) first.set(item.entry.path, item.key);
|
|
1704
|
+
for (const path of first.keys()) taken.add(path);
|
|
1705
|
+
const renames = /* @__PURE__ */ new Map();
|
|
1706
|
+
const media = [];
|
|
1707
|
+
for (const { key, entry, data } of items) {
|
|
1708
|
+
let path = entry.path;
|
|
1709
|
+
if (first.get(entry.path) !== key) {
|
|
1710
|
+
const dot = path.lastIndexOf(".");
|
|
1711
|
+
const stem = dot > path.lastIndexOf("/") ? path.slice(0, dot) : path;
|
|
1712
|
+
const ext = dot > path.lastIndexOf("/") ? path.slice(dot) : "";
|
|
1713
|
+
path = `${stem}-${entry.hash.slice(0, 8)}${ext}`;
|
|
1714
|
+
for (let n = 2; taken.has(path); n++) path = `${stem}-${entry.hash.slice(0, 8)}-${n}${ext}`;
|
|
1715
|
+
taken.add(path);
|
|
1716
|
+
if (entry.b !== void 0) {
|
|
1717
|
+
const map = renames.get(entry.b) ?? /* @__PURE__ */ new Map();
|
|
1718
|
+
map.set(entry.path, path);
|
|
1719
|
+
renames.set(entry.b, map);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
media.push({
|
|
1723
|
+
key,
|
|
1724
|
+
path,
|
|
1725
|
+
hash: entry.hash,
|
|
1726
|
+
declared: { type: entry.ct, byDefault: entry.d },
|
|
1727
|
+
data
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
return { media, renames };
|
|
1731
|
+
}
|
|
1732
|
+
function renameTargets(rels, baseDir, renames) {
|
|
1733
|
+
return rels.replace(/<(?:\w+:)?Relationship\b[^>]*>/g, (tag) => {
|
|
1734
|
+
const target = attrOf(tag, "Target");
|
|
1735
|
+
if (target === void 0 || attrOf(tag, "TargetMode") === "External") return tag;
|
|
1736
|
+
const next = renames.get(resolveTarget(baseDir, target));
|
|
1737
|
+
if (next === void 0) return tag;
|
|
1738
|
+
const value = target.startsWith("/") ? `/${next}` : relativeTarget(baseDir, next);
|
|
1739
|
+
return tag.replace(
|
|
1740
|
+
/(\sTarget\s*=\s*)(?:"[^"]*"|'[^']*')/,
|
|
1741
|
+
(_m, head) => `${head}"${value}"`
|
|
1742
|
+
);
|
|
890
1743
|
});
|
|
891
1744
|
}
|
|
1745
|
+
|
|
1746
|
+
// visio/collab/read.ts
|
|
892
1747
|
function readSharedDrawing(shared) {
|
|
1748
|
+
assertSchemaVersion(shared);
|
|
893
1749
|
if (isSharedDrawingEmpty(shared)) return void 0;
|
|
894
1750
|
const pagesPath = str(shared.meta.get("pagesPath"));
|
|
895
1751
|
const pagesOpen = str(shared.meta.get("pagesOpen"));
|
|
@@ -901,25 +1757,52 @@ function readSharedDrawing(shared) {
|
|
|
901
1757
|
const body = bodyEntry(shared.bodies.get(key));
|
|
902
1758
|
return entry && body ? [{ key, pos: entry.pos, entry, body }] : [];
|
|
903
1759
|
});
|
|
904
|
-
const
|
|
905
|
-
const
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1760
|
+
const renum = readRenum(shared);
|
|
1761
|
+
const fixups = [];
|
|
1762
|
+
const {
|
|
1763
|
+
ids: pageIds,
|
|
1764
|
+
fresh: freshPages,
|
|
1765
|
+
claims: pageClaims
|
|
1766
|
+
} = assignIds(
|
|
1767
|
+
alive.map((p) => ({
|
|
1768
|
+
key: p.key,
|
|
1769
|
+
id: p.entry.id,
|
|
1770
|
+
fixed: fixedId(renum, p.key, p.entry.id)
|
|
1771
|
+
}))
|
|
1772
|
+
);
|
|
1773
|
+
for (const p of [...alive].sort((a, b) => compare(a.key, b.key))) {
|
|
1774
|
+
const value = renumRecord(renum, p.key, p.entry, freshPages.get(p.key), pageClaims.has(p.key));
|
|
1775
|
+
if (value) fixups.push({ map: "renum", key: p.key, value });
|
|
912
1776
|
}
|
|
913
1777
|
const shapesByPage = /* @__PURE__ */ new Map();
|
|
914
1778
|
for (const [full, value] of shared.shapes) {
|
|
915
|
-
const
|
|
916
|
-
if (
|
|
1779
|
+
const parts2 = split(full, 1);
|
|
1780
|
+
if (!parts2 || shared.dead.has(full)) continue;
|
|
917
1781
|
const entry = shapeEntry(value);
|
|
918
1782
|
if (!entry) continue;
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1783
|
+
const map = shapesByPage.get(parts2[0]) ?? /* @__PURE__ */ new Map();
|
|
1784
|
+
map.set(parts2[1], entry);
|
|
1785
|
+
shapesByPage.set(parts2[0], map);
|
|
1786
|
+
}
|
|
1787
|
+
const cellsByPage = /* @__PURE__ */ new Map();
|
|
1788
|
+
for (const [full, value] of shared.cells) {
|
|
1789
|
+
const parts2 = split(full, 2);
|
|
1790
|
+
const entry = parts2 && cellEntry(value);
|
|
1791
|
+
if (!parts2 || !entry) continue;
|
|
1792
|
+
const [page, shape, path] = parts2;
|
|
1793
|
+
const shapes = cellsByPage.get(page) ?? /* @__PURE__ */ new Map();
|
|
1794
|
+
const cells = shapes.get(shape) ?? /* @__PURE__ */ new Map();
|
|
1795
|
+
cells.set(path, entry);
|
|
1796
|
+
shapes.set(shape, cells);
|
|
1797
|
+
cellsByPage.set(page, shapes);
|
|
1798
|
+
}
|
|
1799
|
+
const renumByScope = /* @__PURE__ */ new Map();
|
|
1800
|
+
for (const [full, entry] of renum) {
|
|
1801
|
+
const parts2 = split(full, 1);
|
|
1802
|
+
if (!parts2) continue;
|
|
1803
|
+
const map = renumByScope.get(parts2[0]) ?? /* @__PURE__ */ new Map();
|
|
1804
|
+
map.set(parts2[1], entry);
|
|
1805
|
+
renumByScope.set(parts2[0], map);
|
|
923
1806
|
}
|
|
924
1807
|
const connectsByPage = /* @__PURE__ */ new Map();
|
|
925
1808
|
for (const [full, value] of shared.connects) {
|
|
@@ -930,24 +1813,25 @@ function readSharedDrawing(shared) {
|
|
|
930
1813
|
list.push({ key: full, entry });
|
|
931
1814
|
connectsByPage.set(full.slice(0, slash), list);
|
|
932
1815
|
}
|
|
1816
|
+
const { masters, remap: masterRemap, fixups: masterFixups } = resolveMasters(shared, renum);
|
|
1817
|
+
fixups.push(...masterFixups);
|
|
1818
|
+
const { media, renames } = resolveMedia(shared);
|
|
1819
|
+
const mastersPath = str(shared.meta.get("mastersPath"));
|
|
1820
|
+
const mastersOpen = str(shared.meta.get("mastersOpen"));
|
|
1821
|
+
const mastersClose = str(shared.meta.get("mastersClose"));
|
|
1822
|
+
const pagesDir = dirName(pagesPath);
|
|
933
1823
|
const pages = [];
|
|
934
1824
|
for (const page of byPosition(alive)) {
|
|
935
1825
|
const finalId = pageIds.get(page.key);
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
key: item.key,
|
|
946
|
-
entry,
|
|
947
|
-
from: from?.remap.get(entry.fi) ?? entry.fi,
|
|
948
|
-
to: to?.remap.get(entry.ti) ?? entry.ti
|
|
949
|
-
});
|
|
950
|
-
}
|
|
1826
|
+
const resolved = resolveShapes({
|
|
1827
|
+
scope: page.key,
|
|
1828
|
+
shapes: shapesByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1829
|
+
cells: cellsByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1830
|
+
renum: renumByScope.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1831
|
+
masterRemap
|
|
1832
|
+
});
|
|
1833
|
+
fixups.push(...resolved.fixups);
|
|
1834
|
+
const connects = resolveConnects(connectsByPage.get(page.key), resolved.shapes);
|
|
951
1835
|
let xml = page.entry.xml;
|
|
952
1836
|
const open = /^<[^>]*>/.exec(xml)?.[0];
|
|
953
1837
|
if (open) {
|
|
@@ -956,46 +1840,361 @@ function readSharedDrawing(shared) {
|
|
|
956
1840
|
if (back !== void 0) next = setAttr(next, "BackPage", back);
|
|
957
1841
|
xml = next + xml.slice(open.length);
|
|
958
1842
|
}
|
|
1843
|
+
const rename = page.body.b !== void 0 ? renames.get(page.body.b) : void 0;
|
|
1844
|
+
const body = rename && page.body.rels !== void 0 ? { ...page.body, rels: renameTargets(page.body.rels, pagesDir, rename) } : page.body;
|
|
1845
|
+
const contentSignature = hashTexts([
|
|
1846
|
+
body.shell,
|
|
1847
|
+
body.rels ?? "\0",
|
|
1848
|
+
resolved.xml,
|
|
1849
|
+
...connectSignature(connects)
|
|
1850
|
+
]);
|
|
959
1851
|
pages.push({
|
|
960
1852
|
key: page.key,
|
|
961
1853
|
id: finalId,
|
|
962
1854
|
...page.entry.back !== void 0 ? { back: page.entry.back } : {},
|
|
963
1855
|
xml,
|
|
964
|
-
body
|
|
965
|
-
shapes,
|
|
966
|
-
|
|
1856
|
+
body,
|
|
1857
|
+
shapes: resolved.shapes,
|
|
1858
|
+
shapesXml: resolved.xml,
|
|
1859
|
+
connects,
|
|
1860
|
+
signature: hashTexts([xml, contentSignature]),
|
|
1861
|
+
contentSignature
|
|
967
1862
|
});
|
|
968
1863
|
}
|
|
1864
|
+
const mastersDir = mastersPath !== void 0 ? dirName(mastersPath) : pagesDir;
|
|
1865
|
+
const finalMasters = masters.map((m) => {
|
|
1866
|
+
const batch = shared.masters.get(m.key)?.b;
|
|
1867
|
+
const rename = typeof batch === "string" ? renames.get(batch) : void 0;
|
|
1868
|
+
const scope = masterScope(m.key);
|
|
1869
|
+
const resolved = resolveShapes({
|
|
1870
|
+
scope,
|
|
1871
|
+
shapes: shapesByPage.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1872
|
+
cells: cellsByPage.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1873
|
+
renum: renumByScope.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1874
|
+
masterRemap: /* @__PURE__ */ new Map()
|
|
1875
|
+
});
|
|
1876
|
+
fixups.push(...resolved.fixups);
|
|
1877
|
+
return {
|
|
1878
|
+
...m,
|
|
1879
|
+
...rename && m.rels !== void 0 ? { rels: renameTargets(m.rels, mastersDir, rename) } : {},
|
|
1880
|
+
shapes: resolved.shapes,
|
|
1881
|
+
shapesXml: resolved.xml,
|
|
1882
|
+
connects: resolveConnects(connectsByPage.get(scope), resolved.shapes)
|
|
1883
|
+
};
|
|
1884
|
+
});
|
|
969
1885
|
const parts = /* @__PURE__ */ new Map();
|
|
970
1886
|
for (const [path, value] of shared.parts) if (typeof value === "string") parts.set(path, value);
|
|
971
|
-
|
|
1887
|
+
const baseSignature = hashTexts([
|
|
1888
|
+
pagesPath,
|
|
1889
|
+
pagesOpen,
|
|
1890
|
+
pagesClose,
|
|
1891
|
+
mastersPath ?? "",
|
|
1892
|
+
mastersOpen ?? "",
|
|
1893
|
+
mastersClose ?? "",
|
|
1894
|
+
...pages.map((p) => `${p.key}:${p.id}:${p.xml}`),
|
|
1895
|
+
...finalMasters.flatMap((m) => [
|
|
1896
|
+
m.key,
|
|
1897
|
+
m.id,
|
|
1898
|
+
m.xml,
|
|
1899
|
+
m.part,
|
|
1900
|
+
m.rels ?? "\0",
|
|
1901
|
+
m.shapesXml,
|
|
1902
|
+
...connectSignature(m.connects)
|
|
1903
|
+
]),
|
|
1904
|
+
...media.flatMap((m) => [m.path, m.hash, m.declared.type, String(m.declared.byDefault)]),
|
|
1905
|
+
...[...parts].flatMap(([path, data]) => [path, data])
|
|
1906
|
+
]);
|
|
1907
|
+
const signature = hashTexts([
|
|
1908
|
+
baseSignature,
|
|
1909
|
+
...pages.map((p) => `${p.key}:${p.contentSignature}`)
|
|
1910
|
+
]);
|
|
1911
|
+
return {
|
|
1912
|
+
pagesPath,
|
|
1913
|
+
pagesOpen,
|
|
1914
|
+
pagesClose,
|
|
1915
|
+
pages,
|
|
1916
|
+
...mastersPath !== void 0 && mastersOpen !== void 0 && mastersClose !== void 0 ? { mastersPath, mastersOpen, mastersClose } : {},
|
|
1917
|
+
masters: finalMasters,
|
|
1918
|
+
media,
|
|
1919
|
+
parts,
|
|
1920
|
+
signature,
|
|
1921
|
+
baseSignature,
|
|
1922
|
+
fixups
|
|
1923
|
+
};
|
|
972
1924
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1925
|
+
|
|
1926
|
+
// visio/collab/write-shapes.ts
|
|
1927
|
+
function syncEntry(ctx, map, mapKey, id, content, room, roomContent, local, stamp = false) {
|
|
1928
|
+
ctx.now.set(id, content);
|
|
1929
|
+
const base = ctx.keys.known.get(id);
|
|
1930
|
+
const own = base === void 0 ? !room || roomContent() !== content : base !== content;
|
|
1931
|
+
if (own || !room) {
|
|
1932
|
+
const value = local();
|
|
1933
|
+
ctx.write(map, mapKey, stamp ? { ...value, b: ctx.batch } : value);
|
|
1934
|
+
} else {
|
|
1935
|
+
const pos = local().pos;
|
|
1936
|
+
ctx.write(map, mapKey, pos === void 0 ? room : { ...room, pos });
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
function groupPositions(items, current) {
|
|
1940
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1941
|
+
for (const item of items) groups.set(item.group, [...groups.get(item.group) ?? [], item.key]);
|
|
1942
|
+
const out = /* @__PURE__ */ new Map();
|
|
1943
|
+
for (const list of groups.values())
|
|
1944
|
+
for (const [key, pos] of assignPositions(list, current)) out.set(key, pos);
|
|
1945
|
+
return out;
|
|
1946
|
+
}
|
|
1947
|
+
function syncConnects(ctx, connects) {
|
|
1948
|
+
for (const connect of connects) {
|
|
1949
|
+
ctx.now.set(connectId(connect.key), "");
|
|
1950
|
+
if (!ctx.keys.known.has(connectId(connect.key)) || !ctx.shared.connects.has(connect.key))
|
|
1951
|
+
ctx.write(ctx.shared.connects, connect.key, connect.entry);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
function syncShapes(ctx, page) {
|
|
1955
|
+
const { shared } = ctx;
|
|
1956
|
+
const shapePos = groupPositions(
|
|
1957
|
+
page.shapes.map((s) => ({ key: s.key, group: s.parent ?? "" })),
|
|
1958
|
+
(key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
|
|
1959
|
+
);
|
|
1960
|
+
for (const shape of page.shapes) {
|
|
1961
|
+
const full = `${page.key}/${shape.key}`;
|
|
1962
|
+
const room = shapeEntry(shared.shapes.get(full));
|
|
1963
|
+
const parent = shape.parent;
|
|
1964
|
+
syncEntry(
|
|
1965
|
+
ctx,
|
|
1966
|
+
shared.shapes,
|
|
1967
|
+
full,
|
|
1968
|
+
shapeId(page.key, shape.key),
|
|
1969
|
+
shellContent({ parent, open: shape.open }),
|
|
1970
|
+
room,
|
|
1971
|
+
() => shellContent(room),
|
|
1972
|
+
() => ({
|
|
1973
|
+
pos: shapePos.get(shape.key),
|
|
1974
|
+
...parent !== void 0 ? { parent } : {},
|
|
1975
|
+
open: shape.open,
|
|
1976
|
+
b: room?.b ?? ctx.batch
|
|
1977
|
+
})
|
|
1978
|
+
);
|
|
1979
|
+
const piecePos = groupPositions(
|
|
1980
|
+
shape.pieces.map((p) => ({ key: p.path, group: p.parent })),
|
|
1981
|
+
(path) => cellEntry(shared.cells.get(`${full}/${path}`))?.pos
|
|
1982
|
+
);
|
|
1983
|
+
for (const piece of shape.pieces) {
|
|
1984
|
+
const cellKey = `${full}/${piece.path}`;
|
|
1985
|
+
const roomCell = cellEntry(shared.cells.get(cellKey));
|
|
1986
|
+
const local = () => ({
|
|
1987
|
+
pos: piecePos.get(piece.path),
|
|
1988
|
+
...piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text },
|
|
1989
|
+
...piece.refs ? { r: piece.refs } : {}
|
|
1990
|
+
});
|
|
1991
|
+
syncEntry(
|
|
1992
|
+
ctx,
|
|
1993
|
+
shared.cells,
|
|
1994
|
+
cellKey,
|
|
1995
|
+
cellId(page.key, shape.key, piece.path),
|
|
1996
|
+
entryContent(piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text }),
|
|
1997
|
+
roomCell,
|
|
1998
|
+
() => entryContent(roomCell),
|
|
1999
|
+
local
|
|
2000
|
+
);
|
|
982
2001
|
}
|
|
983
|
-
const ids = item.ids.map((id) => remap.get(id) ?? id);
|
|
984
|
-
for (const id of ids) used.add(id);
|
|
985
|
-
done.set(item.key, {
|
|
986
|
-
key: item.key,
|
|
987
|
-
id: ids[0] ?? "",
|
|
988
|
-
xml: renumberShape(item.xml, remap),
|
|
989
|
-
remap,
|
|
990
|
-
ids
|
|
991
|
-
});
|
|
992
2002
|
}
|
|
993
|
-
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
// visio/collab/write-parts.ts
|
|
2006
|
+
var mediaKey = (hash, path) => `${hash}|${path}`;
|
|
2007
|
+
function syncMasters(ctx, snapshot) {
|
|
2008
|
+
const { shared } = ctx;
|
|
2009
|
+
const pos = assignPositions(
|
|
2010
|
+
snapshot.masters.map((m) => m.key),
|
|
2011
|
+
(key) => masterEntry(shared.masters.get(key))?.pos
|
|
2012
|
+
);
|
|
2013
|
+
for (const master of snapshot.masters) {
|
|
2014
|
+
const room = masterEntry(shared.masters.get(master.key));
|
|
2015
|
+
syncEntry(
|
|
2016
|
+
ctx,
|
|
2017
|
+
shared.masters,
|
|
2018
|
+
master.key,
|
|
2019
|
+
masterId(master.key),
|
|
2020
|
+
masterContent({ ...master, print: fingerprint(master.part) }),
|
|
2021
|
+
room,
|
|
2022
|
+
() => masterContent({
|
|
2023
|
+
...room,
|
|
2024
|
+
print: fingerprint(fromBase64(room.part))
|
|
2025
|
+
}),
|
|
2026
|
+
() => ({
|
|
2027
|
+
pos: pos.get(master.key),
|
|
2028
|
+
id: master.id,
|
|
2029
|
+
xml: master.xml,
|
|
2030
|
+
part: toBase64(master.part),
|
|
2031
|
+
...master.rels !== void 0 ? { rels: master.rels } : {}
|
|
2032
|
+
}),
|
|
2033
|
+
true
|
|
2034
|
+
);
|
|
2035
|
+
syncShapes(ctx, { key: masterScope(master.key), shapes: master.shapes });
|
|
2036
|
+
syncConnects(ctx, master.connects);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
function syncMedia(ctx, snapshot) {
|
|
2040
|
+
const { shared } = ctx;
|
|
2041
|
+
for (const item of snapshot.media) {
|
|
2042
|
+
const known = ctx.keys.mediaKeys.get(item.path);
|
|
2043
|
+
const key = known?.startsWith(`${item.hash}|`) ? known : mediaKey(item.hash, item.path);
|
|
2044
|
+
ctx.now.set(mediaId(key), "");
|
|
2045
|
+
if (!mediaEntry(shared.media.get(key))) {
|
|
2046
|
+
ctx.write(shared.media, key, {
|
|
2047
|
+
path: item.path,
|
|
2048
|
+
hash: item.hash,
|
|
2049
|
+
ct: item.ct,
|
|
2050
|
+
d: item.d,
|
|
2051
|
+
b: ctx.batch
|
|
2052
|
+
});
|
|
2053
|
+
shared.blobs.set(item.hash, toBase64(item.data));
|
|
2054
|
+
} else if (!shared.blobs.has(item.hash)) shared.blobs.set(item.hash, toBase64(item.data));
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function syncParts(ctx, snapshot) {
|
|
2058
|
+
const { shared, keys } = ctx;
|
|
2059
|
+
for (const [path, data] of snapshot.parts) {
|
|
2060
|
+
const print = fingerprint(data);
|
|
2061
|
+
if (keys.partPrints.get(path) === print) continue;
|
|
2062
|
+
ctx.write(shared.parts, path, toBase64(data));
|
|
2063
|
+
keys.partPrints.set(path, print);
|
|
2064
|
+
}
|
|
2065
|
+
let removed = 0;
|
|
2066
|
+
for (const path of [...keys.partPrints.keys()])
|
|
2067
|
+
if (!snapshot.parts.has(path)) {
|
|
2068
|
+
shared.parts.delete(path);
|
|
2069
|
+
keys.partPrints.delete(path);
|
|
2070
|
+
removed++;
|
|
2071
|
+
}
|
|
2072
|
+
return removed;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// visio/collab/write.ts
|
|
2076
|
+
function removeScope(shared, name) {
|
|
2077
|
+
shared.renum.delete(name);
|
|
2078
|
+
for (const map of [shared.shapes, shared.cells, shared.connects, shared.renum])
|
|
2079
|
+
for (const key of [...map.keys()]) if (key.startsWith(`${name}/`)) map.delete(key);
|
|
2080
|
+
}
|
|
2081
|
+
function removePage(shared, name) {
|
|
2082
|
+
shared.dead.set(name, true);
|
|
2083
|
+
for (const map of [shared.pages, shared.bodies]) map.delete(name);
|
|
2084
|
+
removeScope(shared, name);
|
|
2085
|
+
}
|
|
2086
|
+
function writeSharedDrawing(shared, snapshot, keys) {
|
|
2087
|
+
assertSchemaVersion(shared);
|
|
2088
|
+
let writes = 0;
|
|
2089
|
+
const write = (map, key, value) => {
|
|
2090
|
+
if (setIfChanged(map, key, value)) writes++;
|
|
2091
|
+
};
|
|
2092
|
+
const now = /* @__PURE__ */ new Map();
|
|
2093
|
+
const ctx = { shared, keys, now, batch: keys.batch(), write };
|
|
2094
|
+
write(shared.meta, "v", SCHEMA_VERSION);
|
|
2095
|
+
write(shared.meta, "pagesPath", snapshot.pagesPath);
|
|
2096
|
+
write(shared.meta, "pagesOpen", snapshot.pagesOpen);
|
|
2097
|
+
write(shared.meta, "pagesClose", snapshot.pagesClose);
|
|
2098
|
+
if (snapshot.mastersPath !== void 0) {
|
|
2099
|
+
write(shared.meta, "mastersPath", snapshot.mastersPath);
|
|
2100
|
+
write(shared.meta, "mastersOpen", snapshot.mastersOpen);
|
|
2101
|
+
write(shared.meta, "mastersClose", snapshot.mastersClose);
|
|
2102
|
+
}
|
|
2103
|
+
const pagePos = assignPositions(
|
|
2104
|
+
snapshot.pages.map((p) => p.key),
|
|
2105
|
+
(key) => pageEntry(shared.pages.get(key))?.pos
|
|
2106
|
+
);
|
|
2107
|
+
for (const page of snapshot.pages) {
|
|
2108
|
+
const room = pageEntry(shared.pages.get(page.key));
|
|
2109
|
+
syncEntry(
|
|
2110
|
+
ctx,
|
|
2111
|
+
shared.pages,
|
|
2112
|
+
page.key,
|
|
2113
|
+
pageId(page.key),
|
|
2114
|
+
pageContent(page),
|
|
2115
|
+
room,
|
|
2116
|
+
() => pageContent(room),
|
|
2117
|
+
() => ({
|
|
2118
|
+
pos: pagePos.get(page.key),
|
|
2119
|
+
id: page.id,
|
|
2120
|
+
...page.back !== void 0 ? { back: page.back } : {},
|
|
2121
|
+
xml: page.xml
|
|
2122
|
+
})
|
|
2123
|
+
);
|
|
2124
|
+
const roomBody = bodyEntry(shared.bodies.get(page.key));
|
|
2125
|
+
syncEntry(
|
|
2126
|
+
ctx,
|
|
2127
|
+
shared.bodies,
|
|
2128
|
+
page.key,
|
|
2129
|
+
bodyId(page.key),
|
|
2130
|
+
bodyContent(page),
|
|
2131
|
+
roomBody,
|
|
2132
|
+
() => bodyContent(roomBody),
|
|
2133
|
+
() => ({ shell: page.shell, ...page.rels !== void 0 ? { rels: page.rels } : {} }),
|
|
2134
|
+
true
|
|
2135
|
+
);
|
|
2136
|
+
syncShapes(ctx, page);
|
|
2137
|
+
syncConnects(ctx, page.connects);
|
|
2138
|
+
}
|
|
2139
|
+
syncMasters(ctx, snapshot);
|
|
2140
|
+
syncMedia(ctx, snapshot);
|
|
2141
|
+
for (const id of keys.known.keys()) {
|
|
2142
|
+
if (now.has(id)) continue;
|
|
2143
|
+
const name = id.slice(2);
|
|
2144
|
+
switch (id.slice(0, 2)) {
|
|
2145
|
+
case "p:":
|
|
2146
|
+
removePage(shared, name);
|
|
2147
|
+
keys.forgetPage(name);
|
|
2148
|
+
writes++;
|
|
2149
|
+
break;
|
|
2150
|
+
case "s:": {
|
|
2151
|
+
const slash = name.indexOf("/");
|
|
2152
|
+
const page = name.slice(0, slash);
|
|
2153
|
+
if (!now.has(page.startsWith(masterScope("")) ? masterId(page.slice(2)) : pageId(page)))
|
|
2154
|
+
break;
|
|
2155
|
+
shared.dead.set(name, true);
|
|
2156
|
+
shared.shapes.delete(name);
|
|
2157
|
+
keys.forgetShape(page, name.slice(slash + 1));
|
|
2158
|
+
writes++;
|
|
2159
|
+
break;
|
|
2160
|
+
}
|
|
2161
|
+
case "f:":
|
|
2162
|
+
if (shared.cells.has(name)) {
|
|
2163
|
+
shared.cells.delete(name);
|
|
2164
|
+
writes++;
|
|
2165
|
+
}
|
|
2166
|
+
break;
|
|
2167
|
+
case "c:":
|
|
2168
|
+
if (shared.connects.has(name)) {
|
|
2169
|
+
shared.connects.delete(name);
|
|
2170
|
+
writes++;
|
|
2171
|
+
}
|
|
2172
|
+
break;
|
|
2173
|
+
case "m:":
|
|
2174
|
+
if (shared.masters.has(name)) {
|
|
2175
|
+
shared.masters.delete(name);
|
|
2176
|
+
removeScope(shared, masterScope(name));
|
|
2177
|
+
writes++;
|
|
2178
|
+
}
|
|
2179
|
+
keys.forgetMaster(name);
|
|
2180
|
+
break;
|
|
2181
|
+
case "i:":
|
|
2182
|
+
if (shared.media.has(name)) {
|
|
2183
|
+
shared.media.delete(name);
|
|
2184
|
+
writes++;
|
|
2185
|
+
}
|
|
2186
|
+
break;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
keys.known = now;
|
|
2190
|
+
writes += syncParts(ctx, snapshot);
|
|
2191
|
+
return writes;
|
|
994
2192
|
}
|
|
995
2193
|
|
|
996
2194
|
// visio/collab/bind.ts
|
|
997
2195
|
var VISIO_EDIT_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:edit");
|
|
998
2196
|
var VISIO_SYNC_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:sync");
|
|
2197
|
+
var VISIO_FIXUP_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:fixup");
|
|
999
2198
|
function bindDrawingSession(host, editor, options = {}) {
|
|
1000
2199
|
const { doc } = host;
|
|
1001
2200
|
const shared = sharedDrawing(doc);
|
|
@@ -1015,6 +2214,12 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1015
2214
|
let settled = false;
|
|
1016
2215
|
let localDirty = false;
|
|
1017
2216
|
let remoteDirty = false;
|
|
2217
|
+
let incompatible = false;
|
|
2218
|
+
let queued = false;
|
|
2219
|
+
let queuedDone;
|
|
2220
|
+
const schedule = options.schedule ?? ((run) => {
|
|
2221
|
+
setTimeout(run, 0);
|
|
2222
|
+
});
|
|
1018
2223
|
let running;
|
|
1019
2224
|
const report = (error) => options.onError?.(error);
|
|
1020
2225
|
const publish = async () => {
|
|
@@ -1033,7 +2238,14 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1033
2238
|
const rebuild = async () => {
|
|
1034
2239
|
const resolved = readSharedDrawing(shared);
|
|
1035
2240
|
if (!resolved) return;
|
|
2241
|
+
if (resolved.fixups.length && host.canWrite())
|
|
2242
|
+
doc.transact(() => applyFixups(shared, resolved.fixups), VISIO_FIXUP_ORIGIN);
|
|
1036
2243
|
const version = editor.version();
|
|
2244
|
+
if (keys.applied?.signature === resolved.signature && keys.applied.version === version) return;
|
|
2245
|
+
const before = keys.applied;
|
|
2246
|
+
const change = before && before.version === version && before.base === resolved.baseSignature ? {
|
|
2247
|
+
pages: resolved.pages.filter((page) => before.pages.get(page.key) !== page.contentSignature).map((page) => page.id)
|
|
2248
|
+
} : void 0;
|
|
1037
2249
|
const composed = await composeDrawing(resolved, editor.exportBytes(), keys);
|
|
1038
2250
|
if (disposed) return;
|
|
1039
2251
|
if (editor.busy() || editor.version() !== version) {
|
|
@@ -1041,15 +2253,21 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1041
2253
|
return;
|
|
1042
2254
|
}
|
|
1043
2255
|
try {
|
|
1044
|
-
await editor.applyRemote(composed.bytes);
|
|
2256
|
+
await editor.applyRemote(composed.bytes, change);
|
|
1045
2257
|
} catch (error) {
|
|
1046
2258
|
if (editor.busy()) remoteDirty = true;
|
|
1047
2259
|
else report(error);
|
|
1048
2260
|
return;
|
|
1049
2261
|
}
|
|
1050
2262
|
composed.commit();
|
|
2263
|
+
keys.applied = {
|
|
2264
|
+
signature: composed.signature,
|
|
2265
|
+
version: editor.version(),
|
|
2266
|
+
base: resolved.baseSignature,
|
|
2267
|
+
pages: new Map(resolved.pages.map((page) => [page.key, page.contentSignature]))
|
|
2268
|
+
};
|
|
1051
2269
|
};
|
|
1052
|
-
const blocked = () => disposed || !settled || editor.busy();
|
|
2270
|
+
const blocked = () => disposed || incompatible || !settled || editor.busy();
|
|
1053
2271
|
const pending = () => !blocked() && (localDirty && host.canWrite() || remoteDirty && !localDirty);
|
|
1054
2272
|
const loop = async () => {
|
|
1055
2273
|
while (pending()) {
|
|
@@ -1062,6 +2280,7 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1062
2280
|
await rebuild();
|
|
1063
2281
|
}
|
|
1064
2282
|
} catch (error) {
|
|
2283
|
+
if (error instanceof SchemaVersionError) incompatible = true;
|
|
1065
2284
|
report(error);
|
|
1066
2285
|
}
|
|
1067
2286
|
}
|
|
@@ -1088,18 +2307,30 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1088
2307
|
}
|
|
1089
2308
|
pump();
|
|
1090
2309
|
};
|
|
2310
|
+
const queueRemote = () => {
|
|
2311
|
+
if (queued) return;
|
|
2312
|
+
queued = true;
|
|
2313
|
+
queuedDone = new Promise(
|
|
2314
|
+
(resolve) => schedule(() => {
|
|
2315
|
+
queued = false;
|
|
2316
|
+
remoteDirty = true;
|
|
2317
|
+
resolve();
|
|
2318
|
+
pump();
|
|
2319
|
+
})
|
|
2320
|
+
);
|
|
2321
|
+
};
|
|
1091
2322
|
const afterTransaction = (transaction) => {
|
|
1092
2323
|
if (disposed) return;
|
|
1093
2324
|
const origin = transaction.origin;
|
|
1094
|
-
if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN)
|
|
2325
|
+
if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN || origin === VISIO_FIXUP_ORIGIN)
|
|
2326
|
+
return;
|
|
1095
2327
|
const changed = transaction.changed;
|
|
1096
2328
|
if (!types.some((type) => changed.has(type))) return;
|
|
1097
2329
|
if (!settled) {
|
|
1098
2330
|
if (!isSharedDrawingEmpty(shared)) settle();
|
|
1099
2331
|
return;
|
|
1100
2332
|
}
|
|
1101
|
-
|
|
1102
|
-
pump();
|
|
2333
|
+
queueRemote();
|
|
1103
2334
|
};
|
|
1104
2335
|
doc.on("afterTransaction", afterTransaction);
|
|
1105
2336
|
const stops = [
|
|
@@ -1117,7 +2348,10 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1117
2348
|
];
|
|
1118
2349
|
if (host.synced || host.canWrite()) settle();
|
|
1119
2350
|
const idle = async () => {
|
|
1120
|
-
while (running)
|
|
2351
|
+
while (running || queued) {
|
|
2352
|
+
if (queued) await queuedDone;
|
|
2353
|
+
if (running) await running;
|
|
2354
|
+
}
|
|
1121
2355
|
};
|
|
1122
2356
|
const replay = async (kind) => {
|
|
1123
2357
|
await idle();
|
|
@@ -1149,4 +2383,4 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1149
2383
|
};
|
|
1150
2384
|
}
|
|
1151
2385
|
|
|
1152
|
-
export { BODIES, CONNECTS, DEAD, DrawingKeys, META, PAGES, PARTS, SCHEMA_VERSION, SHAPES, VISIO_EDIT_ORIGIN, VISIO_SYNC_ORIGIN, bindDrawingSession, composeDrawing, isSharedDrawingEmpty, readSharedDrawing, sharedDrawing, snapshotDrawing, writeSharedDrawing };
|
|
2386
|
+
export { BLOBS, BODIES, CELLS, CONNECTS, DEAD, DrawingKeys, MASTERS, MEDIA, META, PAGES, PARTS, RENUM, SCHEMA_VERSION, SHAPES, SchemaVersionError, VISIO_EDIT_ORIGIN, VISIO_FIXUP_ORIGIN, VISIO_SYNC_ORIGIN, applyFixups, bindDrawingSession, composeDrawing, isSharedDrawingEmpty, readSharedDrawing, sharedDrawing, snapshotDrawing, writeSharedDrawing };
|