reamkit 1.11.0 → 1.12.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.
Files changed (32) hide show
  1. package/dist/esm/core/converter/facade.js +1 -1
  2. package/dist/esm/core/converter/project.js +1 -0
  3. package/dist/esm/core/document-model/index.d.ts +1 -1
  4. package/dist/esm/core/document-model/types.d.ts +23 -0
  5. package/dist/esm/core/ir/features.d.ts +1 -0
  6. package/dist/esm/core/ir/features.js +1 -0
  7. package/dist/esm/core/ir/flow.d.ts +3 -1
  8. package/dist/esm/core/po-helpers.d.ts +2 -0
  9. package/dist/esm/core/po-helpers.js +14 -1
  10. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  11. package/dist/esm/core/spreadsheet-model/types.d.ts +16 -0
  12. package/dist/esm/excel/pivot-table-parser.d.ts +2 -0
  13. package/dist/esm/excel/pivot-table-parser.js +68 -0
  14. package/dist/esm/excel/print-model.js +28 -6
  15. package/dist/esm/excel/xlsx-reader.js +33 -2
  16. package/dist/esm/html/html-writer.js +52 -2
  17. package/dist/esm/layout/page-doc.d.ts +1 -0
  18. package/dist/esm/layout/styled-layout.d.ts +8 -1
  19. package/dist/esm/layout/styled-layout.js +111 -5
  20. package/dist/esm/pdf/styled-page-emitter.js +38 -0
  21. package/dist/esm/pptx/pptx-reader.d.ts +2 -0
  22. package/dist/esm/pptx/pptx-reader.js +30 -3
  23. package/dist/esm/pptx/slide-parser.d.ts +8 -2
  24. package/dist/esm/pptx/slide-parser.js +80 -12
  25. package/dist/esm/word/document-parser.d.ts +17 -2
  26. package/dist/esm/word/document-parser.js +178 -18
  27. package/dist/esm/word/docx-reader.js +54 -4
  28. package/dist/esm/word/docx-writer.js +84 -1
  29. package/dist/esm/word/drawing-parser.d.ts +7 -0
  30. package/dist/esm/word/drawing-parser.js +13 -0
  31. package/dist/esm/word/index.d.ts +2 -1
  32. package/package.json +1 -1
@@ -44,9 +44,10 @@ function isOutOfFlowFloat(f) {
44
44
  return f !== void 0 && f.wrap !== "topAndBottom";
45
45
  }
46
46
  var FOOTNOTE_RULE_WIDTH = 144;
47
- function assignNoteNumbers(body) {
47
+ function assignNoteNumbers(body, commentIds) {
48
48
  const footnotes = /* @__PURE__ */ new Map();
49
49
  const endnotes = /* @__PURE__ */ new Map();
50
+ const comments = /* @__PURE__ */ new Map();
50
51
  const paragraphFootnotes = /* @__PURE__ */ new Set();
51
52
  const numberRun = (run, n) => ({
52
53
  ...run,
@@ -56,8 +57,17 @@ function assignNoteNumbers(body) {
56
57
  verticalAlign: "superscript"
57
58
  }
58
59
  });
60
+ const commentMarkerRun = (run, n) => ({
61
+ ...run,
62
+ text: `[${n}]`,
63
+ ...run.commentRef !== void 0 && commentIds?.has(run.commentRef) ? { anchor: `comment-${n}` } : {},
64
+ properties: {
65
+ ...run.properties,
66
+ verticalAlign: "superscript"
67
+ }
68
+ });
59
69
  const mapParagraph = (paragraph) => {
60
- if (!paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0)) return paragraph;
70
+ if (!paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0 || r.commentRef !== void 0)) return paragraph;
61
71
  return {
62
72
  ...paragraph,
63
73
  runs: paragraph.runs.map((run) => {
@@ -77,6 +87,14 @@ function assignNoteNumbers(body) {
77
87
  }
78
88
  return numberRun(run, n);
79
89
  }
90
+ if (run.commentRef !== void 0) {
91
+ let n = comments.get(run.commentRef);
92
+ if (n === void 0) {
93
+ n = comments.size + 1;
94
+ comments.set(run.commentRef, n);
95
+ }
96
+ return commentMarkerRun(run, n);
97
+ }
80
98
  return run;
81
99
  })
82
100
  };
@@ -117,7 +135,7 @@ function assignNoteNumbers(body) {
117
135
  return el;
118
136
  };
119
137
  const hasRefs = (els) => els.some((el) => {
120
- if (el.kind === "paragraph") return el.paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0);
138
+ if (el.kind === "paragraph") return el.paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0 || r.commentRef !== void 0);
121
139
  if (el.kind === "table") return el.table.rows.some((row) => row.cells.some((c) => hasRefs(c.content)));
122
140
  if (el.kind === "shape" && el.shape.text) return hasRefs(el.shape.text.content);
123
141
  return false;
@@ -126,12 +144,14 @@ function assignNoteNumbers(body) {
126
144
  body,
127
145
  footnotes,
128
146
  endnotes,
147
+ comments,
129
148
  deferredFootnotes: []
130
149
  };
131
150
  return {
132
151
  body: body.map((el) => mapElement(el, true)),
133
152
  footnotes,
134
153
  endnotes,
154
+ comments,
135
155
  deferredFootnotes: [...footnotes.keys()].filter((id) => !paragraphFootnotes.has(id))
136
156
  };
137
157
  }
@@ -169,9 +189,62 @@ function substituteNoteNumber(content, n) {
169
189
  }
170
190
  }, ...out.slice(1)];
171
191
  }
192
+ function flattenCommentText(content) {
193
+ const lines = [];
194
+ const visit = (els) => {
195
+ for (const el of els) if (el.kind === "paragraph") lines.push(el.paragraph.runs.map((r) => r.text).join(""));
196
+ else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
197
+ };
198
+ visit(content);
199
+ return lines.join("\n").trim();
200
+ }
201
+ function buildCommentNotes(numbers, comments) {
202
+ const out = /* @__PURE__ */ new Map();
203
+ for (const [id, n] of numbers) {
204
+ const c = comments.get(id);
205
+ if (!c) continue;
206
+ out.set(`comment-${n}`, {
207
+ ...c.author !== void 0 ? { author: c.author } : {},
208
+ contents: flattenCommentText(c.content)
209
+ });
210
+ }
211
+ return out;
212
+ }
213
+ function commentTailBlocks(comment, n, opts) {
214
+ const who = [comment.author, comment.date].filter((s) => s !== void 0 && s.length > 0).join(", ");
215
+ const inReplyTo = opts?.parentN !== void 0 ? ` (in reply to [${opts.parentN}])` : "";
216
+ const resolved = opts?.done ? " (resolved)" : "";
217
+ const labelRun = {
218
+ text: who ? `[${n}] ${who}${inReplyTo}${resolved}: ` : `[${n}]${inReplyTo}${resolved} `,
219
+ properties: {}
220
+ };
221
+ const bm = `comment-${n}`;
222
+ const indent = opts?.depth && opts.depth > 0 ? { indentLeft: pt(18 * opts.depth) } : {};
223
+ const first = comment.content[0];
224
+ if (first && first.kind === "paragraph") return [{
225
+ kind: "paragraph",
226
+ paragraph: {
227
+ ...first.paragraph,
228
+ properties: {
229
+ ...first.paragraph.properties,
230
+ ...indent
231
+ },
232
+ runs: [labelRun, ...first.paragraph.runs],
233
+ bookmarks: [bm, ...first.paragraph.bookmarks ?? []]
234
+ }
235
+ }, ...comment.content.slice(1)];
236
+ return [{
237
+ kind: "paragraph",
238
+ paragraph: {
239
+ properties: { ...indent },
240
+ runs: [labelRun],
241
+ bookmarks: [bm]
242
+ }
243
+ }, ...comment.content];
244
+ }
172
245
  function layoutStyledDocument(body, options) {
173
246
  const sectionList = resolveSectionList(body, options);
174
- const noteAssigned = assignNoteNumbers(applyNumbering(body, options.numbering));
247
+ const noteAssigned = assignNoteNumbers(applyNumbering(body, options.numbering), options.comments ? new Set(options.comments.keys()) : void 0);
175
248
  const numberedBody = noteAssigned.body;
176
249
  const numberedHeadersFooters = applyNumberingToHeadersFooters(options.headersFooters, options.numbering);
177
250
  const pdfaProfile = options.pdfA ? parsePdfAProfile(options.pdfA) : void 0;
@@ -229,8 +302,35 @@ function layoutStyledDocument(body, options) {
229
302
  });
230
303
  }
231
304
  for (const note of tailNotes.sort((a, b) => a.n - b.n)) for (const el of substituteNoteNumber(note.content, note.n)) blocks.push(layoutBodyElement(el, options, fontResources, imageResources, lastCtx.contentWidth, lastCtx.pageContentHeight));
305
+ const commentNums = noteAssigned.comments;
306
+ const threadDepth = (id) => {
307
+ let depth = 0;
308
+ const seen = new Set([id]);
309
+ let cur = options.comments?.get(id)?.parentId;
310
+ while (cur !== void 0 && commentNums.has(cur) && !seen.has(cur)) {
311
+ depth++;
312
+ seen.add(cur);
313
+ cur = options.comments?.get(cur)?.parentId;
314
+ }
315
+ return depth;
316
+ };
317
+ const commentTail = [...commentNums].map(([id, n]) => ({
318
+ id,
319
+ comment: options.comments?.get(id),
320
+ n
321
+ })).filter((e) => e.comment !== void 0).sort((a, b) => a.n - b.n);
322
+ for (const { id, comment, n } of commentTail) {
323
+ const parentId = comment.parentId;
324
+ const parentN = parentId !== void 0 && commentNums.has(parentId) ? commentNums.get(parentId) : void 0;
325
+ for (const el of commentTailBlocks(comment, n, {
326
+ ...parentN !== void 0 ? { parentN } : {},
327
+ depth: threadDepth(id),
328
+ ...comment.done ? { done: true } : {}
329
+ })) blocks.push(layoutBodyElement(el, options, fontResources, imageResources, lastCtx.contentWidth, lastCtx.pageContentHeight));
330
+ }
232
331
  }
233
332
  const bookmarks = /* @__PURE__ */ new Map();
333
+ const commentNotes = options.commentAnnotations && options.comments ? buildCommentNotes(noteAssigned.comments, options.comments) : void 0;
234
334
  const reflowParagraph = (paragraph, width, widths) => layoutParagraphBlock(paragraph, options, fontResources, imageResources, width, widths);
235
335
  return {
236
336
  pages: paginateSections(blocks, sectionCtxs, structBuilder, options.language ?? "en-US", notePlan, bookmarks, reflowParagraph),
@@ -242,7 +342,8 @@ function layoutStyledDocument(body, options) {
242
342
  sectionCtxs,
243
343
  pdfaProfile,
244
344
  tagged,
245
- bookmarks
345
+ bookmarks,
346
+ ...commentNotes ? { commentNotes } : {}
246
347
  }
247
348
  };
248
349
  }
@@ -756,6 +857,7 @@ function collectImageResources(body, headersFooters, options) {
756
857
  for (const hf of headersFooters.values()) visit(hf);
757
858
  for (const note of options.footnotes?.values() ?? []) visit(note);
758
859
  for (const note of options.endnotes?.values() ?? []) visit(note);
860
+ for (const comment of options.comments?.values() ?? []) visit(comment.content);
759
861
  const flattenAlpha = options.pdfA ? parsePdfAProfile(options.pdfA).part === 1 : false;
760
862
  let counter = 0;
761
863
  for (const resourceId of seen) {
@@ -916,6 +1018,7 @@ function collectFontResources(body, headersFooters, options) {
916
1018
  for (const hf of headersFooters.values()) visit(hf);
917
1019
  for (const note of options.footnotes?.values() ?? []) visit(note);
918
1020
  for (const note of options.endnotes?.values() ?? []) visit(note);
1021
+ for (const comment of options.comments?.values() ?? []) visit(comment.content);
919
1022
  if (used.size === 0) {
920
1023
  const regular = options.registry.resolveByStyle(false, false);
921
1024
  used.set(regular.variant, {
@@ -1086,6 +1189,7 @@ function tokenizePlansLtr(plans) {
1086
1189
  });
1087
1190
  continue;
1088
1191
  }
1192
+ const highlight = (plan.run.commentRangeRefs?.length ?? 0) > 0;
1089
1193
  for (const t of tokenizeText(plan.run.text)) tokens.push({
1090
1194
  kind: "text",
1091
1195
  text: t.text,
@@ -1094,6 +1198,7 @@ function tokenizePlansLtr(plans) {
1094
1198
  ...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
1095
1199
  ...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
1096
1200
  ...plan.run.listMarker ? { listMarker: true } : {},
1201
+ ...highlight ? { highlight: true } : {},
1097
1202
  resolvedRun: plan.resolvedRun,
1098
1203
  font: plan.font,
1099
1204
  fontSizePt: plan.fontSizePt,
@@ -1148,6 +1253,7 @@ function tokenizePlansBidi(plans, realLevels) {
1148
1253
  ...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
1149
1254
  ...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
1150
1255
  ...plan.run.listMarker ? { listMarker: true } : {},
1256
+ ...(plan.run.commentRangeRefs?.length ?? 0) > 0 ? { highlight: true } : {},
1151
1257
  resolvedRun: plan.resolvedRun,
1152
1258
  font: plan.font,
1153
1259
  fontSizePt: plan.fontSizePt,
@@ -33,6 +33,7 @@ async function emitStyledPdfEncrypted(laid, options, doc, encrypt) {
33
33
  function assembleStyledPdf(laid, options, doc) {
34
34
  const { pages: renderedPages } = laid;
35
35
  const { structBuilder, sectionCtxs, pdfaProfile, tagged } = laid.pdf;
36
+ const commentNotes = !pdfaProfile && !structBuilder ? laid.pdf.commentNotes : void 0;
36
37
  const docInfo = options.pdfUA && !options.info?.title ? {
37
38
  ...options.info,
38
39
  title: "Untitled document"
@@ -158,6 +159,24 @@ function assembleStyledPdf(laid, options, doc) {
158
159
  annotParentCount++;
159
160
  }
160
161
  annots.push(ref(annotRef.id));
162
+ const note = l.anchor !== void 0 ? commentNotes?.get(l.anchor) : void 0;
163
+ if (note) {
164
+ const textAnnot = doc.add(dict({
165
+ Type: name("Annot"),
166
+ Subtype: name("Text"),
167
+ Name: name("Comment"),
168
+ Rect: [
169
+ l.rect[0],
170
+ l.rect[1],
171
+ l.rect[2],
172
+ l.rect[3]
173
+ ],
174
+ F: 28,
175
+ Contents: note.contents,
176
+ ...note.author !== void 0 ? { T: note.author } : {}
177
+ }));
178
+ annots.push(ref(textAnnot.id));
179
+ }
161
180
  }
162
181
  if (annots.length > 0) {
163
182
  pageEntries["Annots"] = annots;
@@ -624,6 +643,25 @@ function emitPageContent(page, tagging, gradientNames) {
624
643
  const text = tok.bidiLevel % 2 === 1 ? reverseByCodePoint(tok.text) : tok.text;
625
644
  return tok.font.measure.encodeTextAsCidHex(text);
626
645
  };
646
+ if (line.tokens.some((t) => t.kind === "text" && t.highlight === true)) {
647
+ if (inBT) {
648
+ out.push("ET");
649
+ inBT = false;
650
+ }
651
+ const hlAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
652
+ const hlDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
653
+ const [hr, hg, hb] = hexToRgb01("fff3a3");
654
+ out.push("q");
655
+ out.push(`${formatNumber(hr)} ${formatNumber(hg)} ${formatNumber(hb)} rg`);
656
+ let hx = originX;
657
+ for (const tok of line.tokens) {
658
+ const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
659
+ if (tok.kind === "text" && tok.highlight === true) out.push(`${formatNumber(hx)} ${formatNumber(baselineY - hlDescent)} ${formatNumber(w)} ${formatNumber(hlAscent + hlDescent)} re`);
660
+ hx += w;
661
+ }
662
+ out.push("f");
663
+ out.push("Q");
664
+ }
627
665
  if (extraPerSpace > 0 || hasImageToken || hasMathToken || hasRtl) {
628
666
  const order = hasRtl ? lineVisualOrder(line) : line.tokens.map((_, i) => i);
629
667
  let x = originX;
@@ -1,4 +1,6 @@
1
1
  import { DocumentReader, ReadResult } from '../core/ir/adapters.js';
2
2
  import { FlowDoc } from '../core/ir/flow.js';
3
+ import { PoNode } from '../core/po-helpers.js';
3
4
  export declare function readPptx(bytes: Uint8Array): ReadResult<FlowDoc>;
5
+ export declare function parseXml(data: Uint8Array): Array<PoNode>;
4
6
  export declare const pptxReader: DocumentReader<FlowDoc>;
@@ -3,8 +3,8 @@ import { ResourceStore } from "../core/ir/resources.js";
3
3
  import { FEATURES } from "../core/ir/features.js";
4
4
  import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
5
5
  import "../core/style-cascade/index.js";
6
+ import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs } from "../core/po-helpers.js";
6
7
  import { bytesInclude } from "../core/bytes.js";
7
- import { poAttr, poChildren, poIntAttr, poIs } from "../core/po-helpers.js";
8
8
  import { DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
9
9
  import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
10
10
  import { parseTheme } from "../core/drawingml/theme-parser.js";
@@ -81,7 +81,12 @@ function readPptx(bytes) {
81
81
  colors: styles.colors,
82
82
  resolveImage: makeSlideImageResolver(pkg, part.path, resources),
83
83
  resolveChart: makeSlideChartResolver(pkg, part.path, charts, styles.colors),
84
- resolveHyperlink: makeHyperlinkResolver(pkg, part.path)
84
+ resolveHyperlink: makeHyperlinkResolver(pkg, part.path),
85
+ resolveDiagram: makeSlideDiagramResolver(pkg, part.path),
86
+ onLoss: (loss) => losses.push(loss.where ? loss : {
87
+ ...loss,
88
+ where: `slide ${i + 1}`
89
+ })
85
90
  };
86
91
  body.push(...parseSlide(part.data, ctx, styles.background, pageW, pageH));
87
92
  }
@@ -167,6 +172,28 @@ function makeSlideChartResolver(pkg, slidePath, charts, colors) {
167
172
  return key;
168
173
  };
169
174
  }
175
+ function makeSlideDiagramResolver(pkg, slidePath) {
176
+ const cache = /* @__PURE__ */ new Map();
177
+ return (relId) => {
178
+ if (cache.has(relId)) return cache.get(relId);
179
+ let spTree;
180
+ const dataRel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
181
+ const data = dataRel ? pkg.resolveRelatedPart(slidePath, dataRel) : void 0;
182
+ if (data) {
183
+ const drawRel = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
184
+ const draw = drawRel ? pkg.resolveRelatedPart(data.path, drawRel) : void 0;
185
+ if (draw) for (const root of parseXml(draw.data)) {
186
+ const found = poFindDescendant(root, "dsp:spTree");
187
+ if (found) {
188
+ spTree = found;
189
+ break;
190
+ }
191
+ }
192
+ }
193
+ cache.set(relId, spTree);
194
+ return spTree;
195
+ };
196
+ }
170
197
  function slideStylesFor(pkg, slidePath, cache) {
171
198
  const layoutRel = pkg.getPartRelationships(slidePath).find((r) => r.type.endsWith("/slideLayout"));
172
199
  const layout = layoutRel ? pkg.resolveRelatedPart(slidePath, layoutRel) : void 0;
@@ -210,4 +237,4 @@ var pptxReader = {
210
237
  read: (bytes) => readPptx(bytes)
211
238
  };
212
239
  //#endregion
213
- export { pptxReader };
240
+ export { parseXml, pptxReader };
@@ -1,6 +1,6 @@
1
- import { BodyElement, ShapeFill } from '../core/document-model/index.js';
1
+ import { BodyElement, FloatAnchor, ShapeBlock, ShapeFill } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
- import { Pt, ResourceId } from '../core/ir/index.js';
3
+ import { Loss, Pt, ResourceId } from '../core/ir/index.js';
4
4
  import { PoNode } from '../core/po-helpers.js';
5
5
  import { PlaceholderCascade } from './placeholder-cascade.js';
6
6
  import { ShapeBoxEmu } from './sp-helpers.js';
@@ -10,9 +10,15 @@ export interface SlideContext {
10
10
  readonly resolveChart?: (relId: string) => string | undefined;
11
11
  readonly colors?: ColorResolver;
12
12
  readonly resolveHyperlink?: (relId: string) => string | undefined;
13
+ readonly resolveDiagram?: (relId: string) => PoNode | undefined;
14
+ readonly onLoss?: (loss: Loss) => void;
13
15
  }
16
+ type LinkResolver = ((relId: string) => string | undefined) | undefined;
14
17
  type GroupTransform = (box: ShapeBoxEmu) => ShapeBoxEmu;
15
18
  export declare function parseSlideShapes(container: PoNode, ctx?: SlideContext, transform?: GroupTransform): Array<BodyElement>;
19
+ export declare function diagramTransform(spTree: PoNode, frame: ShapeBoxEmu): GroupTransform;
20
+ export declare function noDiagramOverrideLoss(where?: string): Loss;
21
+ export declare function parseDiagramDrawing(spTree: PoNode, transform: GroupTransform, makeFloat: (box: ShapeBoxEmu) => FloatAnchor, colors: ColorResolver, resolveLink: LinkResolver): Array<ShapeBlock>;
16
22
  export declare function parseBackgroundFill(bg: PoNode, colors: ColorResolver): ShapeFill | undefined;
17
23
  export declare function backdropElement(fill: ShapeFill, widthPt: Pt, heightPt: Pt): BodyElement;
18
24
  export {};
@@ -1,11 +1,13 @@
1
1
  import { emuToPt } from "../core/ir/units.js";
2
+ import { FEATURES } from "../core/ir/features.js";
2
3
  import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poText } from "../core/po-helpers.js";
3
4
  import { defaultColorResolver, resolveColorNode } from "../core/drawingml/colors.js";
4
- import { parseCustGeom, parseFill, parseLine, parsePrstGeom } from "../word/drawing-parser.js";
5
5
  import { boxFromXfrm, parsePh, parseXfrmBox, rPrToRunProps } from "./sp-helpers.js";
6
+ import { parseCustGeom, parseFill, parseLine, parsePrstGeom } from "../word/drawing-parser.js";
6
7
  //#region src/pptx/slide-parser.ts
7
8
  var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
8
9
  var TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
10
+ var DIAGRAM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
9
11
  var ALGN_TO_ALIGNMENT = {
10
12
  l: "left",
11
13
  ctr: "center",
@@ -33,10 +35,8 @@ function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM) {
33
35
  kind: "image",
34
36
  image
35
37
  });
36
- } else if (poIs(child, "p:graphicFrame")) {
37
- const el = parseGraphicFrame(child, ctx, transform);
38
- if (el) out.push(el);
39
- } else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform)));
38
+ } else if (poIs(child, "p:graphicFrame")) out.push(...parseGraphicFrame(child, ctx, transform));
39
+ else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform)));
40
40
  return out;
41
41
  }
42
42
  function composeGroupTransform(grpSp, parent) {
@@ -106,7 +106,7 @@ function parseSp(sp, ctx, transform) {
106
106
  }
107
107
  function parseGraphicFrame(gf, ctx, transform) {
108
108
  const own = boxFromXfrm(poChildren(gf).find((c) => poIs(c, "p:xfrm")));
109
- if (!own) return void 0;
109
+ if (!own) return [];
110
110
  const box = transform(own);
111
111
  const graphicData = poFindDescendant(gf, "a:graphicData");
112
112
  const uri = graphicData ? poAttr(graphicData, "uri") : void 0;
@@ -114,8 +114,8 @@ function parseGraphicFrame(gf, ctx, transform) {
114
114
  const cChart = poFindDescendant(gf, "c:chart");
115
115
  const relId = cChart ? poAttr(cChart, "id") : void 0;
116
116
  const key = relId !== void 0 ? ctx.resolveChart?.(relId) : void 0;
117
- if (key === void 0) return void 0;
118
- return {
117
+ if (key === void 0) return [];
118
+ return [{
119
119
  kind: "chart",
120
120
  chart: {
121
121
  float: floatAt(box),
@@ -124,15 +124,83 @@ function parseGraphicFrame(gf, ctx, transform) {
124
124
  height: emuToPt(box.cy),
125
125
  paragraphProperties: {}
126
126
  }
127
- };
127
+ }];
128
128
  }
129
129
  if (uri === TABLE_URI) {
130
130
  const tbl = poFindDescendant(gf, "a:tbl");
131
- return tbl ? {
131
+ return tbl ? [{
132
132
  kind: "table",
133
133
  table: parseTable(tbl, ctx.colors ?? defaultColorResolver)
134
- } : void 0;
134
+ }] : [];
135
135
  }
136
+ if (uri === DIAGRAM_URI) {
137
+ const relIds = poFindDescendant(gf, "dgm:relIds");
138
+ const dmRelId = relIds ? poAttr(relIds, "dm") : void 0;
139
+ const spTree = dmRelId !== void 0 ? ctx.resolveDiagram?.(dmRelId) : void 0;
140
+ if (!spTree) {
141
+ if (dmRelId !== void 0) ctx.onLoss?.(noDiagramOverrideLoss());
142
+ return [];
143
+ }
144
+ return parseDiagramDrawing(spTree, diagramTransform(spTree, box), floatAt, ctx.colors ?? defaultColorResolver, ctx.resolveHyperlink).map((shape) => ({
145
+ kind: "shape",
146
+ shape
147
+ }));
148
+ }
149
+ return [];
150
+ }
151
+ function diagramTransform(spTree, frame) {
152
+ const grpSpPr = poChildren(spTree).find((c) => poIs(c, "dsp:grpSpPr"));
153
+ const xfrm = grpSpPr ? poChildren(grpSpPr).find((c) => poIs(c, "a:xfrm")) : void 0;
154
+ const chOff = xfrm ? poChildren(xfrm).find((c) => poIs(c, "a:chOff")) : void 0;
155
+ const chExt = xfrm ? poChildren(xfrm).find((c) => poIs(c, "a:chExt")) : void 0;
156
+ const chExtCx = chExt ? poIntAttr(chExt, "cx") : void 0;
157
+ const chExtCy = chExt ? poIntAttr(chExt, "cy") : void 0;
158
+ const chOffX = (chOff ? poIntAttr(chOff, "x") : void 0) ?? 0;
159
+ const chOffY = (chOff ? poIntAttr(chOff, "y") : void 0) ?? 0;
160
+ const sx = chExtCx && chExtCx > 0 ? frame.cx / chExtCx : 1;
161
+ const sy = chExtCy && chExtCy > 0 ? frame.cy / chExtCy : 1;
162
+ return (b) => ({
163
+ x: frame.x + (b.x - chOffX) * sx,
164
+ y: frame.y + (b.y - chOffY) * sy,
165
+ cx: b.cx * sx,
166
+ cy: b.cy * sy
167
+ });
168
+ }
169
+ function noDiagramOverrideLoss(where) {
170
+ return {
171
+ severity: "dropped",
172
+ feature: FEATURES.smartArt,
173
+ detail: "SmartArt diagram has no pre-rendered drawing override; its layout is not reconstructed",
174
+ ...where ? { where } : {}
175
+ };
176
+ }
177
+ function parseDiagramDrawing(spTree, transform, makeFloat, colors, resolveLink) {
178
+ const out = [];
179
+ for (const sp of poChildren(spTree)) {
180
+ if (!poIs(sp, "dsp:sp")) continue;
181
+ const spPr = poChildren(sp).find((c) => poIs(c, "dsp:spPr"));
182
+ const own = parseXfrmBox(spPr);
183
+ if (!own) continue;
184
+ const box = transform(own);
185
+ const txBody = poChildren(sp).find((c) => poIs(c, "dsp:txBody"));
186
+ const text = txBody ? parseTxBody(txBody, void 0, void 0, colors, resolveLink) : void 0;
187
+ const geometry = parseGeometry(spPr);
188
+ const fill = spPr ? parseFill(spPr, colors) : { kind: "none" };
189
+ const line = spPr ? parseLine(spPr, colors) : void 0;
190
+ const visibleLine = line !== void 0 && line.fill !== "none";
191
+ if (!text && fill.kind === "none" && !visibleLine) continue;
192
+ out.push({
193
+ float: makeFloat(box),
194
+ width: emuToPt(box.cx),
195
+ height: emuToPt(box.cy),
196
+ geometry,
197
+ fill,
198
+ ...line ? { line } : {},
199
+ ...text ? { text } : {},
200
+ paragraphProperties: {}
201
+ });
202
+ }
203
+ return out;
136
204
  }
137
205
  function parseBackgroundFill(bg, colors) {
138
206
  const bgPr = poChildren(bg).find((c) => poIs(c, "p:bgPr"));
@@ -356,4 +424,4 @@ function cellFillHex(tcPr, colors) {
356
424
  }
357
425
  }
358
426
  //#endregion
359
- export { backdropElement, parseBackgroundFill, parseSlideShapes };
427
+ export { backdropElement, diagramTransform, noDiagramOverrideLoss, parseBackgroundFill, parseDiagramDrawing, parseSlideShapes };
@@ -1,6 +1,6 @@
1
- import { BodyElement, Section, SectionProperties } from '../core/document-model/index.js';
1
+ import { BodyElement, Comment, Section, SectionProperties } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
- import { ResourceId } from '../core/ir/index.js';
3
+ import { Loss, ResourceId } from '../core/ir/index.js';
4
4
  import { PoNode } from '../core/po-helpers.js';
5
5
  export type ImageResolver = (relId: string) => ResourceId | undefined;
6
6
  export type HyperlinkResolver = (relId: string) => string | undefined;
@@ -8,6 +8,9 @@ export interface ParseContext {
8
8
  readonly resolveColor: ColorResolver;
9
9
  readonly resolveImage?: ImageResolver;
10
10
  readonly resolveHyperlink?: HyperlinkResolver;
11
+ readonly resolveDiagram?: (relId: string) => PoNode | undefined;
12
+ readonly onLoss?: (loss: Loss) => void;
13
+ readonly openCommentRanges?: Set<string>;
11
14
  }
12
15
  export declare const DEFAULT_PARSE_CONTEXT: ParseContext;
13
16
  export declare function parseDocument(documentXml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
@@ -17,3 +20,15 @@ export declare function parseSections(documentXml: Uint8Array): Array<Section>;
17
20
  export declare function parseHeaderFooter(xml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
18
21
  export declare function parseBodyElements(children: ReadonlyArray<PoNode>, ctx?: ParseContext): Array<BodyElement>;
19
22
  export declare function parseNotes(notesXml: Uint8Array, rootTag: 'w:footnotes' | 'w:endnotes', noteTag: 'w:footnote' | 'w:endnote', ctx?: ParseContext): Map<string, Array<BodyElement>>;
23
+ export declare function parseComments(commentsXml: Uint8Array, ctx?: ParseContext): Map<string, Comment>;
24
+ /** A commentsExtended entry, keyed by the comment's last-paragraph w14:paraId. */
25
+ export interface CommentExtension {
26
+ /** The parent comment's paraId — present when this comment is a reply. */
27
+ readonly paraIdParent?: string;
28
+ /** w15:done — the thread is resolved. */
29
+ readonly done: boolean;
30
+ }
31
+ export declare function parseCommentsExtended(xml: Uint8Array): Map<string, CommentExtension>;
32
+ export declare function parseCommentThreads(commentsXml: Uint8Array, commentsExtendedXml: Uint8Array | undefined, ctx?: ParseContext): Map<string, Comment>;
33
+ export declare function parsePeople(xml: Uint8Array): Map<string, string>;
34
+ export declare function applyAuthorIds(comments: Map<string, Comment>, people: Map<string, string>): Map<string, Comment>;