js.documents 2.3.2 → 3.0.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 +27 -14
- package/dist/codecs/registry.d.cts +8 -3
- package/dist/codecs/registry.d.ts +8 -3
- package/dist/convert/canonicalise.cjs +20 -0
- package/dist/convert/canonicalise.d.cts +5 -0
- package/dist/convert/canonicalise.d.ts +5 -0
- package/dist/convert/canonicalise.js +18 -0
- package/dist/convert/composition.cjs +29 -28
- package/dist/convert/composition.d.cts +1 -1
- package/dist/convert/composition.d.ts +1 -1
- package/dist/convert/composition.js +29 -28
- package/dist/convert/convert.cjs +14 -26
- package/dist/convert/convert.d.cts +1 -1
- package/dist/convert/convert.d.ts +1 -1
- package/dist/convert/convert.js +14 -26
- package/dist/convert/decompose.cjs +134 -0
- package/dist/convert/decompose.d.cts +13 -0
- package/dist/convert/decompose.d.ts +13 -0
- package/dist/convert/decompose.js +126 -0
- package/dist/convert/factor-styles.cjs +364 -0
- package/dist/convert/factor-styles.d.cts +6 -0
- package/dist/convert/factor-styles.d.ts +6 -0
- package/dist/convert/factor-styles.js +362 -0
- package/dist/convert/flatten.cjs +137 -0
- package/dist/convert/flatten.d.cts +5 -0
- package/dist/convert/flatten.d.ts +5 -0
- package/dist/convert/flatten.js +136 -0
- package/dist/convert/from-package.cjs +4 -3
- package/dist/convert/from-package.d.cts +2 -1
- package/dist/convert/from-package.d.ts +2 -1
- package/dist/convert/from-package.js +5 -4
- package/dist/convert/local.cjs +1 -1
- package/dist/convert/local.js +1 -1
- package/dist/convert/variant-bridges.cjs +0 -4
- package/dist/convert/variant-bridges.js +1 -5
- package/dist/csv/read.cjs +0 -1
- package/dist/csv/read.js +1 -2
- package/dist/edit/docx/numbering.d.cts +1 -1
- package/dist/edit/docx/numbering.d.ts +1 -1
- package/dist/edit/docx/paragraph.cjs +1 -0
- package/dist/edit/docx/paragraph.js +1 -0
- package/dist/edit/pdf/editor.cjs +1 -2
- package/dist/edit/pdf/editor.d.cts +2 -2
- package/dist/edit/pdf/editor.d.ts +2 -2
- package/dist/edit/pdf/editor.js +1 -2
- package/dist/edit/pdf/item.d.cts +1 -1
- package/dist/edit/pdf/item.d.ts +1 -1
- package/dist/edit/pdf/page.d.cts +2 -2
- package/dist/edit/pdf/page.d.ts +2 -2
- package/dist/edit/pdf/util.d.cts +1 -1
- package/dist/edit/pdf/util.d.ts +1 -1
- package/dist/fonts/registry.d.cts +1 -1
- package/dist/fonts/registry.d.ts +1 -1
- package/dist/index.cjs +10 -15
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +6 -3
- package/dist/{item-Dj6f1VTE.d.cts → item-D9vQKT0T.d.cts} +2 -1
- package/dist/{item-Dj6f1VTE.d.ts → item-D9vQKT0T.d.ts} +2 -1
- package/dist/latex/lint.cjs +3 -2
- package/dist/latex/lint.js +3 -2
- package/dist/layout/drawing.d.cts +2 -1
- package/dist/layout/drawing.d.ts +2 -1
- package/dist/layout/engine.cjs +8 -5
- package/dist/layout/engine.d.cts +2 -1
- package/dist/layout/engine.d.ts +2 -1
- package/dist/layout/engine.js +8 -5
- package/dist/layout/lattice.d.cts +1 -1
- package/dist/layout/lattice.d.ts +1 -1
- package/dist/layout/reconstruct.cjs +0 -5
- package/dist/layout/reconstruct.d.cts +2 -1
- package/dist/layout/reconstruct.d.ts +2 -1
- package/dist/layout/reconstruct.js +0 -5
- package/dist/layout/shared.cjs +2 -1
- package/dist/layout/shared.d.cts +2 -1
- package/dist/layout/shared.d.ts +2 -1
- package/dist/layout/shared.js +2 -1
- package/dist/layout/sheets.d.cts +2 -1
- package/dist/layout/sheets.d.ts +2 -1
- package/dist/layout/slides.d.cts +2 -1
- package/dist/layout/slides.d.ts +2 -1
- package/dist/markdown/render.cjs +0 -1
- package/dist/markdown/render.js +1 -2
- package/dist/model/embedded-drawing.cjs +5 -8
- package/dist/model/embedded-drawing.js +5 -8
- package/dist/model/formula.cjs +0 -2
- package/dist/model/formula.js +0 -2
- package/dist/odb/report/render.cjs +0 -1
- package/dist/odb/report/render.js +1 -2
- package/dist/odb/spreadsheet.cjs +0 -1
- package/dist/odb/spreadsheet.js +1 -2
- package/dist/odf/odg/read.cjs +0 -2
- package/dist/odf/odg/read.js +0 -2
- package/dist/odf/odp/read.cjs +0 -2
- package/dist/odf/odp/read.js +0 -2
- package/dist/odf/ods/read.cjs +0 -2
- package/dist/odf/ods/read.js +0 -2
- package/dist/odf/odt/read.cjs +0 -2
- package/dist/odf/odt/read.js +0 -2
- package/dist/ooxml/docx/read.cjs +0 -2
- package/dist/ooxml/docx/read.js +0 -2
- package/dist/ooxml/pptx/read.cjs +0 -2
- package/dist/ooxml/pptx/read.js +0 -2
- package/dist/svg/read.cjs +8 -11
- package/dist/svg/read.js +8 -11
- package/package.json +6 -6
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { flattenPackage } from "./flatten.js";
|
|
2
|
+
import { canonicalKey } from "./canonicalise.js";
|
|
3
|
+
import { decomposeDrawPage, decomposeSection, decomposeSheet, decomposeSlide } from "./decompose.js";
|
|
4
|
+
//#region src/convert/factor-styles.ts
|
|
5
|
+
const PARAGRAPH_STYLE_KEYS = [
|
|
6
|
+
"alignment",
|
|
7
|
+
"spacingBeforePt",
|
|
8
|
+
"spacingAfterPt",
|
|
9
|
+
"lineSpacing",
|
|
10
|
+
"indentLeftPt",
|
|
11
|
+
"indentFirstLinePt"
|
|
12
|
+
];
|
|
13
|
+
const RUN_STYLE_KEYS = [
|
|
14
|
+
"bold",
|
|
15
|
+
"italic",
|
|
16
|
+
"underline",
|
|
17
|
+
"strike",
|
|
18
|
+
"fontFamily",
|
|
19
|
+
"sizePt",
|
|
20
|
+
"color"
|
|
21
|
+
];
|
|
22
|
+
function isShapeGroupWrapper(wrapper) {
|
|
23
|
+
return !("kind" in wrapper.node);
|
|
24
|
+
}
|
|
25
|
+
function isAnchorGroupWrapper(wrapper) {
|
|
26
|
+
return "kind" in wrapper.node && wrapper.node.kind === "paragraph";
|
|
27
|
+
}
|
|
28
|
+
function isSlideGroupWrapper(wrapper) {
|
|
29
|
+
return "kind" in wrapper.node && wrapper.node.kind === "slide";
|
|
30
|
+
}
|
|
31
|
+
function isDrawPageGroupWrapper(wrapper) {
|
|
32
|
+
return "kind" in wrapper.node && wrapper.node.kind === "drawPage";
|
|
33
|
+
}
|
|
34
|
+
function isHeadingGroup(group) {
|
|
35
|
+
return group.node.headingLevel !== void 0;
|
|
36
|
+
}
|
|
37
|
+
function assemblePackage(content, pages) {
|
|
38
|
+
const envelope = {
|
|
39
|
+
metadata: content.metadata,
|
|
40
|
+
...content.symbolTable !== void 0 ? { symbolTable: content.symbolTable } : {},
|
|
41
|
+
...pages !== void 0 ? { pages: [...pages] } : {}
|
|
42
|
+
};
|
|
43
|
+
switch (content.kind) {
|
|
44
|
+
case "wordprocessing": return mint({
|
|
45
|
+
kind: "wordprocessing",
|
|
46
|
+
...envelope,
|
|
47
|
+
children: content.sections.map(decomposeSection)
|
|
48
|
+
});
|
|
49
|
+
case "presentation": return mint({
|
|
50
|
+
kind: "presentation",
|
|
51
|
+
...envelope,
|
|
52
|
+
children: content.slides.map(decomposeSlide)
|
|
53
|
+
});
|
|
54
|
+
case "spreadsheet": return mint({
|
|
55
|
+
kind: "spreadsheet",
|
|
56
|
+
...envelope,
|
|
57
|
+
children: content.sheets.map(decomposeSheet)
|
|
58
|
+
});
|
|
59
|
+
case "drawing": return mint({
|
|
60
|
+
kind: "drawing",
|
|
61
|
+
...envelope,
|
|
62
|
+
children: content.pages.map(decomposeDrawPage)
|
|
63
|
+
});
|
|
64
|
+
case "formula": return mint({
|
|
65
|
+
kind: "formula",
|
|
66
|
+
...envelope,
|
|
67
|
+
children: [content.formula]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function factorStyles(pkg) {
|
|
72
|
+
return assemblePackage(flattenPackage(pkg), pkg.pages);
|
|
73
|
+
}
|
|
74
|
+
function extentOf(wrapper) {
|
|
75
|
+
if (isShapeGroupWrapper(wrapper)) return flowExtent(wrapper.children);
|
|
76
|
+
if (isAnchorGroupWrapper(wrapper)) return [wrapper.node, ...flowExtent(wrapper.children)];
|
|
77
|
+
if (isSlideGroupWrapper(wrapper)) return wrapper.children.flatMap(extentOf);
|
|
78
|
+
if (isDrawPageGroupWrapper(wrapper)) {
|
|
79
|
+
const paragraphs = [];
|
|
80
|
+
for (const child of wrapper.children) if ("node" in child) paragraphs.push(...extentOf(child));
|
|
81
|
+
return paragraphs;
|
|
82
|
+
}
|
|
83
|
+
return flowExtent(wrapper.children);
|
|
84
|
+
}
|
|
85
|
+
function flowExtent(children) {
|
|
86
|
+
const paragraphs = [];
|
|
87
|
+
for (const child of children) if ("node" in child && "children" in child) paragraphs.push(...extentOf(child));
|
|
88
|
+
else if (child.kind === "paragraph") paragraphs.push(child);
|
|
89
|
+
return paragraphs;
|
|
90
|
+
}
|
|
91
|
+
function paragraphTuple(paragraph, keys) {
|
|
92
|
+
const tuple = {};
|
|
93
|
+
for (const key of keys) if (paragraph[key] !== void 0) tuple[key] = paragraph[key];
|
|
94
|
+
return tuple;
|
|
95
|
+
}
|
|
96
|
+
function runTuple(run, keys) {
|
|
97
|
+
const tuple = {};
|
|
98
|
+
for (const key of keys) if (run[key] !== void 0) tuple[key] = run[key];
|
|
99
|
+
return tuple;
|
|
100
|
+
}
|
|
101
|
+
function commonParagraphKeys(extent, frozen) {
|
|
102
|
+
return PARAGRAPH_STYLE_KEYS.filter((key) => !frozen.has(key) && extent.every((paragraph) => paragraph[key] !== void 0));
|
|
103
|
+
}
|
|
104
|
+
function commonRunKeys(extent, frozen) {
|
|
105
|
+
const runs = extent.flatMap((paragraph) => paragraph.runs);
|
|
106
|
+
if (runs.length === 0) return [];
|
|
107
|
+
return RUN_STYLE_KEYS.filter((key) => !frozen.has(key) && runs.every((run) => run[key] !== void 0));
|
|
108
|
+
}
|
|
109
|
+
function bestParagraphCandidate(extent, keys, factored) {
|
|
110
|
+
const groups = /* @__PURE__ */ new Map();
|
|
111
|
+
for (const paragraph of extent) {
|
|
112
|
+
if (factored.has(paragraph)) continue;
|
|
113
|
+
const tuple = paragraphTuple(paragraph, keys);
|
|
114
|
+
if (Object.keys(tuple).length === 0) continue;
|
|
115
|
+
const key = canonicalKey(tuple);
|
|
116
|
+
const existing = groups.get(key);
|
|
117
|
+
if (existing === void 0) groups.set(key, {
|
|
118
|
+
tuple,
|
|
119
|
+
keys,
|
|
120
|
+
positions: [paragraph]
|
|
121
|
+
});
|
|
122
|
+
else existing.positions.push(paragraph);
|
|
123
|
+
}
|
|
124
|
+
return bestGroup(groups);
|
|
125
|
+
}
|
|
126
|
+
function bestRunCandidate(extent, keys, factored) {
|
|
127
|
+
const groups = /* @__PURE__ */ new Map();
|
|
128
|
+
for (const paragraph of extent) for (const run of paragraph.runs) {
|
|
129
|
+
if (factored.has(run)) continue;
|
|
130
|
+
const tuple = runTuple(run, keys);
|
|
131
|
+
if (Object.keys(tuple).length === 0) continue;
|
|
132
|
+
const key = canonicalKey(tuple);
|
|
133
|
+
const existing = groups.get(key);
|
|
134
|
+
if (existing === void 0) groups.set(key, {
|
|
135
|
+
tuple,
|
|
136
|
+
keys,
|
|
137
|
+
positions: [run]
|
|
138
|
+
});
|
|
139
|
+
else existing.positions.push(run);
|
|
140
|
+
}
|
|
141
|
+
return bestGroup(groups);
|
|
142
|
+
}
|
|
143
|
+
function bestGroup(groups) {
|
|
144
|
+
let best;
|
|
145
|
+
for (const group of groups.values()) {
|
|
146
|
+
if (group.positions.length < 2) continue;
|
|
147
|
+
if (best === void 0 || group.positions.length > best.positions.length) best = group;
|
|
148
|
+
}
|
|
149
|
+
return best;
|
|
150
|
+
}
|
|
151
|
+
function plan(wrapper, visit, frozenParagraphs, frozenRuns, state, entries) {
|
|
152
|
+
const extent = extentOf(wrapper);
|
|
153
|
+
const paragraphCandidate = extent.length > 0 ? bestParagraphCandidate(extent, commonParagraphKeys(extent, frozenParagraphs), state.factoredParagraphs) : void 0;
|
|
154
|
+
const runCandidate = extent.length > 0 ? bestRunCandidate(extent, commonRunKeys(extent, frozenRuns), state.factoredRuns) : void 0;
|
|
155
|
+
const nextFrozenParagraphs = new Set(frozenParagraphs);
|
|
156
|
+
const nextFrozenRuns = new Set(frozenRuns);
|
|
157
|
+
if (paragraphCandidate !== void 0 || runCandidate !== void 0) {
|
|
158
|
+
const content = {
|
|
159
|
+
...paragraphCandidate !== void 0 ? { paragraph: paragraphCandidate.tuple } : {},
|
|
160
|
+
...runCandidate !== void 0 ? { run: runCandidate.tuple } : {}
|
|
161
|
+
};
|
|
162
|
+
const contentKey = canonicalKey(content);
|
|
163
|
+
const existing = entries.get(contentKey);
|
|
164
|
+
if (existing === void 0) entries.set(contentKey, {
|
|
165
|
+
content,
|
|
166
|
+
wrappers: [wrapper],
|
|
167
|
+
frequency: (paragraphCandidate?.positions.length ?? 0) + (runCandidate?.positions.length ?? 0),
|
|
168
|
+
firstVisit: visit.index
|
|
169
|
+
});
|
|
170
|
+
else {
|
|
171
|
+
existing.wrappers.push(wrapper);
|
|
172
|
+
existing.frequency += (paragraphCandidate?.positions.length ?? 0) + (runCandidate?.positions.length ?? 0);
|
|
173
|
+
}
|
|
174
|
+
if (paragraphCandidate !== void 0) {
|
|
175
|
+
for (const paragraph of paragraphCandidate.positions) {
|
|
176
|
+
state.factoredParagraphs.add(paragraph);
|
|
177
|
+
state.paragraphStrips.set(paragraph, paragraphCandidate.keys);
|
|
178
|
+
}
|
|
179
|
+
for (const key of paragraphCandidate.keys) nextFrozenParagraphs.add(key);
|
|
180
|
+
}
|
|
181
|
+
if (runCandidate !== void 0) {
|
|
182
|
+
for (const run of runCandidate.positions) {
|
|
183
|
+
state.factoredRuns.add(run);
|
|
184
|
+
state.runStrips.set(run, runCandidate.keys);
|
|
185
|
+
}
|
|
186
|
+
for (const key of runCandidate.keys) nextFrozenRuns.add(key);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
visit.index += 1;
|
|
190
|
+
for (const child of childWrappers(wrapper)) plan(child, visit, nextFrozenParagraphs, nextFrozenRuns, state, entries);
|
|
191
|
+
}
|
|
192
|
+
function childWrappers(wrapper) {
|
|
193
|
+
if (isShapeGroupWrapper(wrapper) || isAnchorGroupWrapper(wrapper)) {
|
|
194
|
+
const wrappers = [];
|
|
195
|
+
for (const child of wrapper.children) if ("node" in child && "children" in child) wrappers.push(child);
|
|
196
|
+
return wrappers;
|
|
197
|
+
}
|
|
198
|
+
if (isSlideGroupWrapper(wrapper)) return [...wrapper.children];
|
|
199
|
+
if (isDrawPageGroupWrapper(wrapper)) {
|
|
200
|
+
const shapes = [];
|
|
201
|
+
for (const child of wrapper.children) if ("node" in child) shapes.push(child);
|
|
202
|
+
return shapes;
|
|
203
|
+
}
|
|
204
|
+
const wrappers = [];
|
|
205
|
+
for (const child of wrapper.children) if ("node" in child && "children" in child) wrappers.push(child);
|
|
206
|
+
return wrappers;
|
|
207
|
+
}
|
|
208
|
+
function mint(pkg) {
|
|
209
|
+
const state = {
|
|
210
|
+
factoredParagraphs: /* @__PURE__ */ new Set(),
|
|
211
|
+
factoredRuns: /* @__PURE__ */ new Set(),
|
|
212
|
+
wrapperRefs: /* @__PURE__ */ new Map(),
|
|
213
|
+
paragraphStrips: /* @__PURE__ */ new Map(),
|
|
214
|
+
runStrips: /* @__PURE__ */ new Map()
|
|
215
|
+
};
|
|
216
|
+
const entries = /* @__PURE__ */ new Map();
|
|
217
|
+
const visit = { index: 0 };
|
|
218
|
+
const emptyParagraphs = /* @__PURE__ */ new Set();
|
|
219
|
+
const emptyRuns = /* @__PURE__ */ new Set();
|
|
220
|
+
switch (pkg.kind) {
|
|
221
|
+
case "wordprocessing":
|
|
222
|
+
for (const root of pkg.children) plan(root, visit, emptyParagraphs, emptyRuns, state, entries);
|
|
223
|
+
break;
|
|
224
|
+
case "presentation":
|
|
225
|
+
for (const root of pkg.children) plan(root, visit, emptyParagraphs, emptyRuns, state, entries);
|
|
226
|
+
break;
|
|
227
|
+
case "drawing": for (const root of pkg.children) plan(root, visit, emptyParagraphs, emptyRuns, state, entries);
|
|
228
|
+
}
|
|
229
|
+
if (entries.size === 0) return pkg;
|
|
230
|
+
const ordered = [...entries.values()].sort((a, b) => b.frequency - a.frequency || a.firstVisit - b.firstVisit || canonicalKey(a.content).localeCompare(canonicalKey(b.content)));
|
|
231
|
+
const styles = {};
|
|
232
|
+
ordered.forEach((entry, index) => {
|
|
233
|
+
const id = `s${index + 1}`;
|
|
234
|
+
styles[id] = entry.content;
|
|
235
|
+
for (const wrapper of entry.wrappers) state.wrapperRefs.set(wrapper, id);
|
|
236
|
+
});
|
|
237
|
+
switch (pkg.kind) {
|
|
238
|
+
case "wordprocessing": return {
|
|
239
|
+
...pkg,
|
|
240
|
+
styles,
|
|
241
|
+
children: pkg.children.map((group) => rebuildSectionGroup(group, state))
|
|
242
|
+
};
|
|
243
|
+
case "presentation": return {
|
|
244
|
+
...pkg,
|
|
245
|
+
styles,
|
|
246
|
+
children: pkg.children.map((group) => rebuildSlideGroup(group, state))
|
|
247
|
+
};
|
|
248
|
+
case "drawing": return {
|
|
249
|
+
...pkg,
|
|
250
|
+
styles,
|
|
251
|
+
children: pkg.children.map((group) => rebuildDrawPageGroup(group, state))
|
|
252
|
+
};
|
|
253
|
+
case "spreadsheet":
|
|
254
|
+
case "formula": return {
|
|
255
|
+
...pkg,
|
|
256
|
+
styles
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function rebuildSlideGroup(group, state) {
|
|
261
|
+
const children = group.children.map((shape) => rebuildShapeGroup(shape, state));
|
|
262
|
+
const ref = state.wrapperRefs.get(group);
|
|
263
|
+
return ref === void 0 && children.every((child, index) => child === group.children[index]) ? group : {
|
|
264
|
+
node: group.node,
|
|
265
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
266
|
+
children
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function rebuildDrawPageGroup(group, state) {
|
|
270
|
+
const children = group.children.map((child) => "node" in child ? rebuildShapeGroup(child, state) : child);
|
|
271
|
+
const ref = state.wrapperRefs.get(group);
|
|
272
|
+
return ref === void 0 && children.every((child, index) => child === group.children[index]) ? group : {
|
|
273
|
+
node: group.node,
|
|
274
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
275
|
+
children
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function rebuildSectionGroup(group, state) {
|
|
279
|
+
const children = group.children.map((child) => rebuildSectionChild(child, state));
|
|
280
|
+
const ref = state.wrapperRefs.get(group);
|
|
281
|
+
return ref === void 0 && children.every((child, index) => child === group.children[index]) ? group : {
|
|
282
|
+
node: group.node,
|
|
283
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
284
|
+
children
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function rebuildSectionChild(child, state) {
|
|
288
|
+
if ("node" in child && "children" in child) return isHeadingGroup(child) ? rebuildHeadingGroup(child, state, rebuildSectionChild) : rebuildListGroup(child, state, rebuildListChild);
|
|
289
|
+
if (child.kind === "paragraph") return rebuildParagraph(child, state);
|
|
290
|
+
return child;
|
|
291
|
+
}
|
|
292
|
+
function rebuildListChild(child, state) {
|
|
293
|
+
if ("node" in child && "children" in child) return rebuildListGroup(child, state, rebuildListChild);
|
|
294
|
+
if (child.kind === "paragraph") return rebuildParagraph(child, state);
|
|
295
|
+
return child;
|
|
296
|
+
}
|
|
297
|
+
function rebuildShapeGroup(group, state) {
|
|
298
|
+
const children = group.children.map((child) => rebuildListChild(child, state));
|
|
299
|
+
const ref = state.wrapperRefs.get(group);
|
|
300
|
+
return ref === void 0 && children.every((child, index) => child === group.children[index]) ? group : {
|
|
301
|
+
node: group.node,
|
|
302
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
303
|
+
children
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function rebuildHeadingGroup(group, state, rebuildChild) {
|
|
307
|
+
const anchor = rebuildParagraph(group.node, state);
|
|
308
|
+
assertHeadingAnchor(anchor);
|
|
309
|
+
const children = group.children.map((child) => rebuildChild(child, state));
|
|
310
|
+
const ref = state.wrapperRefs.get(group);
|
|
311
|
+
return ref === void 0 && anchor === group.node && children.every((child, index) => child === group.children[index]) ? group : {
|
|
312
|
+
node: anchor,
|
|
313
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
314
|
+
children
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function rebuildListGroup(group, state, rebuildChild) {
|
|
318
|
+
const anchor = rebuildParagraph(group.node, state);
|
|
319
|
+
assertListAnchor(anchor);
|
|
320
|
+
const children = group.children.map((child) => rebuildChild(child, state));
|
|
321
|
+
const ref = state.wrapperRefs.get(group);
|
|
322
|
+
return ref === void 0 && anchor === group.node && children.every((child, index) => child === group.children[index]) ? group : {
|
|
323
|
+
node: anchor,
|
|
324
|
+
...ref !== void 0 ? { style: ref } : {},
|
|
325
|
+
children
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function assertHeadingAnchor(paragraph) {
|
|
329
|
+
if (paragraph.headingLevel === void 0) throw new Error("factorStyles: stripping dropped a heading anchor's headingLevel");
|
|
330
|
+
}
|
|
331
|
+
function assertListAnchor(paragraph) {
|
|
332
|
+
if (paragraph.list === void 0) throw new Error("factorStyles: stripping dropped a list anchor's list membership");
|
|
333
|
+
}
|
|
334
|
+
function rebuildParagraph(paragraph, state) {
|
|
335
|
+
const strips = state.paragraphStrips.get(paragraph);
|
|
336
|
+
const base = strips === void 0 ? paragraph : stripParagraphKeys(paragraph, strips);
|
|
337
|
+
let changed = base !== paragraph;
|
|
338
|
+
const runs = [];
|
|
339
|
+
for (const run of base.runs) {
|
|
340
|
+
const runStrips = state.runStrips.get(run);
|
|
341
|
+
const rebuilt = runStrips === void 0 ? run : stripRunKeys(run, runStrips);
|
|
342
|
+
changed ||= rebuilt !== run;
|
|
343
|
+
runs.push(rebuilt);
|
|
344
|
+
}
|
|
345
|
+
if (!changed) return paragraph;
|
|
346
|
+
return {
|
|
347
|
+
...base,
|
|
348
|
+
runs
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function stripParagraphKeys(paragraph, keys) {
|
|
352
|
+
const copy = { ...paragraph };
|
|
353
|
+
for (const key of keys) delete copy[key];
|
|
354
|
+
return copy;
|
|
355
|
+
}
|
|
356
|
+
function stripRunKeys(run, keys) {
|
|
357
|
+
const copy = { ...run };
|
|
358
|
+
for (const key of keys) delete copy[key];
|
|
359
|
+
return copy;
|
|
360
|
+
}
|
|
361
|
+
//#endregion
|
|
362
|
+
export { assemblePackage, factorStyles };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let document_schema_js = require("document-schema.js");
|
|
3
|
+
//#region src/convert/flatten.ts
|
|
4
|
+
function chainWithRef(chain, group) {
|
|
5
|
+
return group.style === void 0 ? chain : [...chain, group.style];
|
|
6
|
+
}
|
|
7
|
+
function entryOf(styles, chain) {
|
|
8
|
+
if (chain.length === 0) return void 0;
|
|
9
|
+
if (styles === void 0) throw new Error("flattenPackage: a group carries a style ref but the package has no styles table");
|
|
10
|
+
return (0, document_schema_js.resolveStyleChain)(styles, chain);
|
|
11
|
+
}
|
|
12
|
+
function applyEntry(entry, paragraph) {
|
|
13
|
+
const withParagraph = (0, document_schema_js.applyParagraphStyleProperties)(entry.paragraph, paragraph);
|
|
14
|
+
const runProperties = entry.run;
|
|
15
|
+
if (runProperties === void 0) return withParagraph;
|
|
16
|
+
return {
|
|
17
|
+
...withParagraph,
|
|
18
|
+
runs: withParagraph.runs.map((run) => (0, document_schema_js.applyRunStyleProperties)(runProperties, run))
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function flattenPackage(pkg) {
|
|
22
|
+
const styles = pkg.styles;
|
|
23
|
+
const envelope = {
|
|
24
|
+
metadata: pkg.metadata,
|
|
25
|
+
...pkg.symbolTable !== void 0 ? { symbolTable: pkg.symbolTable } : {}
|
|
26
|
+
};
|
|
27
|
+
switch (pkg.kind) {
|
|
28
|
+
case "wordprocessing": return {
|
|
29
|
+
kind: "wordprocessing",
|
|
30
|
+
...envelope,
|
|
31
|
+
sections: pkg.children.map((group) => ({
|
|
32
|
+
...untag(group.node),
|
|
33
|
+
blocks: flattenSectionChildren(styles, chainWithRef([], group), group.children)
|
|
34
|
+
}))
|
|
35
|
+
};
|
|
36
|
+
case "presentation": return {
|
|
37
|
+
kind: "presentation",
|
|
38
|
+
...envelope,
|
|
39
|
+
slides: pkg.children.map((group) => {
|
|
40
|
+
const chain = chainWithRef([], group);
|
|
41
|
+
return {
|
|
42
|
+
...untag(group.node),
|
|
43
|
+
shapes: group.children.map((shape) => flattenShape(styles, chain, shape))
|
|
44
|
+
};
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
case "spreadsheet": return {
|
|
48
|
+
kind: "spreadsheet",
|
|
49
|
+
...envelope,
|
|
50
|
+
sheets: pkg.children.map((group) => {
|
|
51
|
+
const images = [];
|
|
52
|
+
const embedded = [];
|
|
53
|
+
for (const child of group.children) if ("kind" in child) images.push(child);
|
|
54
|
+
else embedded.push(child);
|
|
55
|
+
return {
|
|
56
|
+
...untag(group.node),
|
|
57
|
+
images,
|
|
58
|
+
...embedded.length > 0 ? { embeddedObjects: embedded } : {}
|
|
59
|
+
};
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
case "drawing": return {
|
|
63
|
+
kind: "drawing",
|
|
64
|
+
...envelope,
|
|
65
|
+
pages: pkg.children.map((group) => {
|
|
66
|
+
const chain = chainWithRef([], group);
|
|
67
|
+
const shapes = [];
|
|
68
|
+
const vectors = [];
|
|
69
|
+
for (const child of group.children) if ("node" in child) shapes.push(flattenShape(styles, chain, child));
|
|
70
|
+
else vectors.push(child);
|
|
71
|
+
return {
|
|
72
|
+
...untag(group.node),
|
|
73
|
+
shapes,
|
|
74
|
+
vectors
|
|
75
|
+
};
|
|
76
|
+
})
|
|
77
|
+
};
|
|
78
|
+
case "formula": {
|
|
79
|
+
const first = pkg.children[0];
|
|
80
|
+
if (pkg.children.length !== 1 || first === void 0 || !document_schema_js.ContentFormulaSchema.safeParse(first).success) throw new Error("flattenPackage: a formula package takes exactly one ContentFormula node");
|
|
81
|
+
return {
|
|
82
|
+
kind: "formula",
|
|
83
|
+
...envelope,
|
|
84
|
+
formula: first
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function untag(descriptor) {
|
|
90
|
+
const copy = { ...descriptor };
|
|
91
|
+
delete copy.kind;
|
|
92
|
+
return copy;
|
|
93
|
+
}
|
|
94
|
+
function flattenShape(styles, chain, group) {
|
|
95
|
+
return {
|
|
96
|
+
...group.node,
|
|
97
|
+
blocks: flattenListChildren(styles, chainWithRef(chain, group), group.children)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function flattenSectionChildren(styles, chain, children) {
|
|
101
|
+
const blocks = [];
|
|
102
|
+
for (const child of children) if (isHeadingGroup(child)) {
|
|
103
|
+
const own = chainWithRef(chain, child);
|
|
104
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenSectionChildren(styles, own, child.children));
|
|
105
|
+
} else if (isListGroup(child)) {
|
|
106
|
+
const own = chainWithRef(chain, child);
|
|
107
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenListChildren(styles, own, child.children));
|
|
108
|
+
} else if (child.kind === "paragraph") {
|
|
109
|
+
const entry = entryOf(styles, chain);
|
|
110
|
+
blocks.push(entry === void 0 ? child : applyEntry(entry, child));
|
|
111
|
+
} else blocks.push(child);
|
|
112
|
+
return blocks;
|
|
113
|
+
}
|
|
114
|
+
function flattenListChildren(styles, chain, children) {
|
|
115
|
+
const blocks = [];
|
|
116
|
+
for (const child of children) if (isListGroup(child)) {
|
|
117
|
+
const own = chainWithRef(chain, child);
|
|
118
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenListChildren(styles, own, child.children));
|
|
119
|
+
} else if (child.kind === "paragraph") {
|
|
120
|
+
const entry = entryOf(styles, chain);
|
|
121
|
+
blocks.push(entry === void 0 ? child : applyEntry(entry, child));
|
|
122
|
+
} else blocks.push(child);
|
|
123
|
+
return blocks;
|
|
124
|
+
}
|
|
125
|
+
function isHeadingGroup(child) {
|
|
126
|
+
return "node" in child && "children" in child && child.node.kind === "paragraph" && child.node.headingLevel !== void 0;
|
|
127
|
+
}
|
|
128
|
+
function isListGroup(child) {
|
|
129
|
+
return "node" in child && "children" in child && child.node.kind === "paragraph" && child.node.list !== void 0;
|
|
130
|
+
}
|
|
131
|
+
function resolveAnchor(styles, chain, anchor) {
|
|
132
|
+
const entry = entryOf(styles, chain);
|
|
133
|
+
if (entry === void 0) return anchor;
|
|
134
|
+
return applyEntry(entry, anchor);
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
exports.flattenPackage = flattenPackage;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ContentFormulaSchema, applyParagraphStyleProperties, applyRunStyleProperties, resolveStyleChain } from "document-schema.js";
|
|
2
|
+
//#region src/convert/flatten.ts
|
|
3
|
+
function chainWithRef(chain, group) {
|
|
4
|
+
return group.style === void 0 ? chain : [...chain, group.style];
|
|
5
|
+
}
|
|
6
|
+
function entryOf(styles, chain) {
|
|
7
|
+
if (chain.length === 0) return void 0;
|
|
8
|
+
if (styles === void 0) throw new Error("flattenPackage: a group carries a style ref but the package has no styles table");
|
|
9
|
+
return resolveStyleChain(styles, chain);
|
|
10
|
+
}
|
|
11
|
+
function applyEntry(entry, paragraph) {
|
|
12
|
+
const withParagraph = applyParagraphStyleProperties(entry.paragraph, paragraph);
|
|
13
|
+
const runProperties = entry.run;
|
|
14
|
+
if (runProperties === void 0) return withParagraph;
|
|
15
|
+
return {
|
|
16
|
+
...withParagraph,
|
|
17
|
+
runs: withParagraph.runs.map((run) => applyRunStyleProperties(runProperties, run))
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function flattenPackage(pkg) {
|
|
21
|
+
const styles = pkg.styles;
|
|
22
|
+
const envelope = {
|
|
23
|
+
metadata: pkg.metadata,
|
|
24
|
+
...pkg.symbolTable !== void 0 ? { symbolTable: pkg.symbolTable } : {}
|
|
25
|
+
};
|
|
26
|
+
switch (pkg.kind) {
|
|
27
|
+
case "wordprocessing": return {
|
|
28
|
+
kind: "wordprocessing",
|
|
29
|
+
...envelope,
|
|
30
|
+
sections: pkg.children.map((group) => ({
|
|
31
|
+
...untag(group.node),
|
|
32
|
+
blocks: flattenSectionChildren(styles, chainWithRef([], group), group.children)
|
|
33
|
+
}))
|
|
34
|
+
};
|
|
35
|
+
case "presentation": return {
|
|
36
|
+
kind: "presentation",
|
|
37
|
+
...envelope,
|
|
38
|
+
slides: pkg.children.map((group) => {
|
|
39
|
+
const chain = chainWithRef([], group);
|
|
40
|
+
return {
|
|
41
|
+
...untag(group.node),
|
|
42
|
+
shapes: group.children.map((shape) => flattenShape(styles, chain, shape))
|
|
43
|
+
};
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
case "spreadsheet": return {
|
|
47
|
+
kind: "spreadsheet",
|
|
48
|
+
...envelope,
|
|
49
|
+
sheets: pkg.children.map((group) => {
|
|
50
|
+
const images = [];
|
|
51
|
+
const embedded = [];
|
|
52
|
+
for (const child of group.children) if ("kind" in child) images.push(child);
|
|
53
|
+
else embedded.push(child);
|
|
54
|
+
return {
|
|
55
|
+
...untag(group.node),
|
|
56
|
+
images,
|
|
57
|
+
...embedded.length > 0 ? { embeddedObjects: embedded } : {}
|
|
58
|
+
};
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
case "drawing": return {
|
|
62
|
+
kind: "drawing",
|
|
63
|
+
...envelope,
|
|
64
|
+
pages: pkg.children.map((group) => {
|
|
65
|
+
const chain = chainWithRef([], group);
|
|
66
|
+
const shapes = [];
|
|
67
|
+
const vectors = [];
|
|
68
|
+
for (const child of group.children) if ("node" in child) shapes.push(flattenShape(styles, chain, child));
|
|
69
|
+
else vectors.push(child);
|
|
70
|
+
return {
|
|
71
|
+
...untag(group.node),
|
|
72
|
+
shapes,
|
|
73
|
+
vectors
|
|
74
|
+
};
|
|
75
|
+
})
|
|
76
|
+
};
|
|
77
|
+
case "formula": {
|
|
78
|
+
const first = pkg.children[0];
|
|
79
|
+
if (pkg.children.length !== 1 || first === void 0 || !ContentFormulaSchema.safeParse(first).success) throw new Error("flattenPackage: a formula package takes exactly one ContentFormula node");
|
|
80
|
+
return {
|
|
81
|
+
kind: "formula",
|
|
82
|
+
...envelope,
|
|
83
|
+
formula: first
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function untag(descriptor) {
|
|
89
|
+
const copy = { ...descriptor };
|
|
90
|
+
delete copy.kind;
|
|
91
|
+
return copy;
|
|
92
|
+
}
|
|
93
|
+
function flattenShape(styles, chain, group) {
|
|
94
|
+
return {
|
|
95
|
+
...group.node,
|
|
96
|
+
blocks: flattenListChildren(styles, chainWithRef(chain, group), group.children)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function flattenSectionChildren(styles, chain, children) {
|
|
100
|
+
const blocks = [];
|
|
101
|
+
for (const child of children) if (isHeadingGroup(child)) {
|
|
102
|
+
const own = chainWithRef(chain, child);
|
|
103
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenSectionChildren(styles, own, child.children));
|
|
104
|
+
} else if (isListGroup(child)) {
|
|
105
|
+
const own = chainWithRef(chain, child);
|
|
106
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenListChildren(styles, own, child.children));
|
|
107
|
+
} else if (child.kind === "paragraph") {
|
|
108
|
+
const entry = entryOf(styles, chain);
|
|
109
|
+
blocks.push(entry === void 0 ? child : applyEntry(entry, child));
|
|
110
|
+
} else blocks.push(child);
|
|
111
|
+
return blocks;
|
|
112
|
+
}
|
|
113
|
+
function flattenListChildren(styles, chain, children) {
|
|
114
|
+
const blocks = [];
|
|
115
|
+
for (const child of children) if (isListGroup(child)) {
|
|
116
|
+
const own = chainWithRef(chain, child);
|
|
117
|
+
blocks.push(resolveAnchor(styles, own, child.node), ...flattenListChildren(styles, own, child.children));
|
|
118
|
+
} else if (child.kind === "paragraph") {
|
|
119
|
+
const entry = entryOf(styles, chain);
|
|
120
|
+
blocks.push(entry === void 0 ? child : applyEntry(entry, child));
|
|
121
|
+
} else blocks.push(child);
|
|
122
|
+
return blocks;
|
|
123
|
+
}
|
|
124
|
+
function isHeadingGroup(child) {
|
|
125
|
+
return "node" in child && "children" in child && child.node.kind === "paragraph" && child.node.headingLevel !== void 0;
|
|
126
|
+
}
|
|
127
|
+
function isListGroup(child) {
|
|
128
|
+
return "node" in child && "children" in child && child.node.kind === "paragraph" && child.node.list !== void 0;
|
|
129
|
+
}
|
|
130
|
+
function resolveAnchor(styles, chain, anchor) {
|
|
131
|
+
const entry = entryOf(styles, chain);
|
|
132
|
+
if (entry === void 0) return anchor;
|
|
133
|
+
return applyEntry(entry, anchor);
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { flattenPackage };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_model_geometry = require("../model/geometry.cjs");
|
|
3
|
+
const require_convert_flatten = require("./flatten.cjs");
|
|
3
4
|
const require_layout_shared = require("../layout/shared.cjs");
|
|
4
5
|
require("../layout/sheets.cjs");
|
|
5
6
|
const require_layout_drawing = require("../layout/drawing.cjs");
|
|
@@ -15,7 +16,7 @@ function buildDocumentBytes(pkg, target) {
|
|
|
15
16
|
if (target === "odf") throw new Error("'odf' (a standalone formula document) cannot be built from a DocumentPackage -- there is no ContentDocument-to-odf builder");
|
|
16
17
|
const content = require_codecs_registry.DOCUMENT_FORMAT_CODECS[target].content;
|
|
17
18
|
if (!content?.write) throw new Error(`DocumentFormat '${target}' has no content.write codec in DOCUMENT_FORMAT_CODECS, and is not 'pdf'/'odf' -- this is an internal invariant violation, not a caller error`);
|
|
18
|
-
return require_codecs_registry.requireArrayBufferBytes(content.write(pkg
|
|
19
|
+
return require_codecs_registry.requireArrayBufferBytes(content.write(require_convert_flatten.flattenPackage(pkg)));
|
|
19
20
|
}
|
|
20
21
|
function pageOfFrame(state, frame) {
|
|
21
22
|
return state.pages[frame.pageIndex];
|
|
@@ -173,7 +174,7 @@ function layoutDocumentFromPackage(pkg) {
|
|
|
173
174
|
pages,
|
|
174
175
|
images: {}
|
|
175
176
|
};
|
|
176
|
-
const content = pkg
|
|
177
|
+
const content = require_convert_flatten.flattenPackage(pkg);
|
|
177
178
|
if (content.kind === "wordprocessing") for (const section of content.sections) emitBlocks(state, section.blocks);
|
|
178
179
|
else if (content.kind === "presentation") for (const slide of content.slides) for (const shape of slide.shapes) emitBlocks(state, shape.blocks);
|
|
179
180
|
else if (content.kind === "spreadsheet") for (const sheet of content.sheets) emitSheet(state, sheet);
|
|
@@ -182,7 +183,7 @@ function layoutDocumentFromPackage(pkg) {
|
|
|
182
183
|
for (const shape of drawPage.shapes) emitBlocks(state, shape.blocks);
|
|
183
184
|
}
|
|
184
185
|
return {
|
|
185
|
-
formatVersion:
|
|
186
|
+
formatVersion: pdf_codec.LAYOUT_FORMAT_VERSION,
|
|
186
187
|
metadata: content.metadata,
|
|
187
188
|
pages,
|
|
188
189
|
images: state.images
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DocumentFormat } from "./port.cjs";
|
|
2
|
-
import { DocumentPackage
|
|
2
|
+
import { DocumentPackage } from "document-schema.js";
|
|
3
|
+
import { LayoutDocument } from "pdf-codec";
|
|
3
4
|
//#region src/convert/from-package.d.ts
|
|
4
5
|
declare function buildDocumentBytes(pkg: DocumentPackage, target: DocumentFormat): Uint8Array<ArrayBuffer>;
|
|
5
6
|
declare function layoutDocumentFromPackage(pkg: DocumentPackage): LayoutDocument;
|