reamkit 1.33.1 → 1.34.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 (74) hide show
  1. package/README.md +13 -10
  2. package/dist/esm/core/converter/facade.js +1 -0
  3. package/dist/esm/core/converter/ream.d.ts +6 -6
  4. package/dist/esm/core/converter/ream.js +11 -5
  5. package/dist/esm/core/crypto/index.js +1 -2
  6. package/dist/esm/core/document-model/index.d.ts +1 -1
  7. package/dist/esm/core/document-model/types.d.ts +15 -0
  8. package/dist/esm/core/drawingml/text-warp.d.ts +34 -0
  9. package/dist/esm/core/drawingml/text-warp.js +49 -1
  10. package/dist/esm/core/font/index.d.ts +1 -1
  11. package/dist/esm/core/font/index.js +8 -0
  12. package/dist/esm/core/font/indic-shaper.d.ts +47 -0
  13. package/dist/esm/core/font/indic-shaper.js +1146 -0
  14. package/dist/esm/core/font/indic-table.d.ts +12 -0
  15. package/dist/esm/core/font/indic-table.js +463 -0
  16. package/dist/esm/core/font/measure.d.ts +45 -4
  17. package/dist/esm/core/font/measure.js +253 -14
  18. package/dist/esm/core/font/opentype-lookups.d.ts +214 -0
  19. package/dist/esm/core/font/opentype-lookups.js +1112 -0
  20. package/dist/esm/core/fonts/families.d.ts +4 -0
  21. package/dist/esm/core/fonts/families.js +43 -12
  22. package/dist/esm/core/fonts/provider.js +1 -0
  23. package/dist/esm/core/fonts/remote-fonts.d.ts +4 -2
  24. package/dist/esm/core/fonts/remote-fonts.js +36 -0
  25. package/dist/esm/core/fonts/scripts.d.ts +19 -0
  26. package/dist/esm/core/fonts/scripts.js +96 -1
  27. package/dist/esm/core/numbering/apply.js +12 -8
  28. package/dist/esm/core/style-cascade/index.d.ts +1 -1
  29. package/dist/esm/core/style-cascade/index.js +2 -2
  30. package/dist/esm/core/style-cascade/resolver.d.ts +9 -0
  31. package/dist/esm/core/style-cascade/resolver.js +31 -3
  32. package/dist/esm/core/style-cascade/table.js +3 -8
  33. package/dist/esm/excel/xlsx-to-pdf.js +1 -0
  34. package/dist/esm/index.js +1 -0
  35. package/dist/esm/layout/line-paint.d.ts +5 -4
  36. package/dist/esm/layout/line-paint.js +6 -5
  37. package/dist/esm/layout/page-doc.d.ts +26 -0
  38. package/dist/esm/layout/styled-layout.d.ts +8 -1
  39. package/dist/esm/layout/styled-layout.js +459 -112
  40. package/dist/esm/layout/undrawn.d.ts +18 -0
  41. package/dist/esm/layout/undrawn.js +59 -0
  42. package/dist/esm/pdf/cid-font.d.ts +5 -0
  43. package/dist/esm/pdf/cid-font.js +8 -2
  44. package/dist/esm/pdf/styled-page-emitter.js +117 -28
  45. package/dist/esm/pdf/text-page-renderer.js +1 -0
  46. package/dist/esm/pdf-reader/content.d.ts +1 -1
  47. package/dist/esm/pdf-reader/content.js +48 -13
  48. package/dist/esm/pdf-reader/embedded-fonts.js +1 -0
  49. package/dist/esm/pdf-reader/encodings.d.ts +9 -0
  50. package/dist/esm/pdf-reader/encodings.js +66 -1
  51. package/dist/esm/pdf-reader/face-outlines.js +1 -0
  52. package/dist/esm/pdf-reader/text.d.ts +10 -0
  53. package/dist/esm/pdf-reader/text.js +25 -3
  54. package/dist/esm/pdf-reader/vector.js +2 -2
  55. package/dist/esm/pptx/embedded-fonts.js +1 -0
  56. package/dist/esm/pptx/slide-parser.js +22 -7
  57. package/dist/esm/pptx/sp-helpers.d.ts +3 -2
  58. package/dist/esm/pptx/sp-helpers.js +9 -4
  59. package/dist/esm/svg/svg-text.js +30 -7
  60. package/dist/esm/word/doc/doc-reader.js +148 -57
  61. package/dist/esm/word/doc/doc-text.d.ts +80 -11
  62. package/dist/esm/word/doc/doc-text.js +438 -75
  63. package/dist/esm/word/document-parser.js +48 -28
  64. package/dist/esm/word/docx-to-pdf.d.ts +5 -5
  65. package/dist/esm/word/docx-to-pdf.js +9 -7
  66. package/dist/esm/word/docx-writer.js +3 -5
  67. package/dist/esm/word/font-embed.js +1 -0
  68. package/dist/esm/word/font-table.js +1 -0
  69. package/dist/esm/word/numbering-parser.js +3 -0
  70. package/dist/esm/word/paragraph-properties.js +2 -2
  71. package/dist/esm/word/run-properties.js +2 -2
  72. package/dist/esm/word/xml-helpers.d.ts +18 -0
  73. package/dist/esm/word/xml-helpers.js +48 -1
  74. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
- import { PDF_NULL, PdfName, PdfStream } from "../pdf/objects.js";
1
+ import { PDF_NULL, PdfHexString, PdfName, PdfStream } from "../pdf/objects.js";
2
+ import { pdfTextString } from "./encodings.js";
2
3
  import { buildColorSpaceMap, buildShadingMap } from "./shading.js";
3
4
  import { IDENTITY, interpretContent, multiply } from "./content.js";
4
5
  import { textMarkupOf } from "./annot-draw.js";
@@ -275,8 +276,29 @@ function spacesOf(file, resources) {
275
276
  spaceCache.set(resources, made);
276
277
  return made;
277
278
  }
279
+ /**
280
+ * §14.9.4 — the replacement text of each property list the page's
281
+ * `/Properties` names: the content says `/Span /P1 BDC` and the `/ActualText`
282
+ * is in the resources, not in the stream.
283
+ *
284
+ * @param file The owning file.
285
+ * @param resources The resource dictionary in force.
286
+ * @returns Name → the text, for the lists that hold one.
287
+ */
288
+ function actualTextsOf(file, resources) {
289
+ const out = /* @__PURE__ */ new Map();
290
+ const props = resources ? file.get(resources, "Properties") : void 0;
291
+ if (!(props instanceof Map)) return out;
292
+ for (const [name, value] of props) {
293
+ const list = file.resolve(value);
294
+ const text = list instanceof Map ? file.get(list, "ActualText") : void 0;
295
+ if (text instanceof PdfHexString) out.set(name, pdfTextString(text.bytes));
296
+ else if (typeof text === "string") out.set(name, pdfTextString(Uint8Array.from(text, (c) => c.charCodeAt(0) & 255)));
297
+ }
298
+ return out;
299
+ }
278
300
  function collectRuns(file, resources, content, baseCtm, depth, visiting, out, shown) {
279
- const result = interpretContent(content, buildFonts(file, resources), baseCtm, shadingsOf(file, resources), void 0, spacesOf(file, resources), hiddenProperties(file, resources));
301
+ const result = interpretContent(content, buildFonts(file, resources), baseCtm, shadingsOf(file, resources), void 0, spacesOf(file, resources), hiddenProperties(file, resources), actualTextsOf(file, resources));
280
302
  out.push(...result.texts.map((r) => withPatternColour(file, resources, r, visiting)));
281
303
  if (shown) addShown(shown, result.shown);
282
304
  if (depth >= MAX_FORM_DEPTH) return;
@@ -411,4 +433,4 @@ function inRect(x, y, r) {
411
433
  return x >= r[0] - 1 && x <= r[2] + 1 && y >= r[1] - 2 && y <= r[3] + 2;
412
434
  }
413
435
  //#endregion
414
- export { buildFonts, extractPageText };
436
+ export { actualTextsOf, buildFonts, extractPageText };
@@ -4,7 +4,7 @@ import { buildAlphaMap, buildColorSpaceMap, buildShadingMap, gradientShading, sh
4
4
  import { IDENTITY, interpretContent, multiply } from "./content.js";
5
5
  import { appearanceContent, collectPageAppearances } from "./annots.js";
6
6
  import { hiddenProperties, hiddenXObject } from "./optional-content.js";
7
- import { buildFonts } from "./text.js";
7
+ import { actualTextsOf, buildFonts } from "./text.js";
8
8
  import { patternTint, tintedHex } from "./pattern-tint.js";
9
9
  //#region src/pdf-reader/vector.ts
10
10
  function paintedVectors(file, page) {
@@ -53,7 +53,7 @@ function paintedVectors(file, page) {
53
53
  const xobjects = resources ? file.get(resources, "XObject") : PDF_NULL;
54
54
  const xobjDict = xobjects instanceof Map ? xobjects : void 0;
55
55
  const maps = mapsOf(resources);
56
- const result = interpretContent(content, buildFonts(file, resources), baseCtm, maps.shadings, maps.alphas, maps.spaces, hiddenProperties(file, resources));
56
+ const result = interpretContent(content, buildFonts(file, resources), baseCtm, maps.shadings, maps.alphas, maps.spaces, hiddenProperties(file, resources), actualTextsOf(file, resources));
57
57
  for (const paint of result.shadings) {
58
58
  if (out.length >= MAX_VECTORS) break;
59
59
  const dict = resources ? file.get(resources, "Shading") : PDF_NULL;
@@ -1,4 +1,5 @@
1
1
  import { FontRegistry } from "../core/font/font-registry.js";
2
+ import "../core/font/index.js";
2
3
  import { poAttr, poChildren, poIs } from "../core/po-helpers.js";
3
4
  //#region src/pptx/embedded-fonts.ts
4
5
  var REL_FONT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font";
@@ -40,7 +40,7 @@ function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM, s
40
40
  const out = [];
41
41
  for (const child of poChildren(container)) {
42
42
  if (skipPlaceholders && isPlaceholder(child)) continue;
43
- if (poIs(child, "p:sp")) {
43
+ if (poIs(child, "p:sp") || poIs(child, "p:cxnSp")) {
44
44
  const shape = parseSp(child, ctx, transform);
45
45
  if (shape) out.push({
46
46
  kind: "shape",
@@ -89,6 +89,15 @@ function pictureAsShape(pic) {
89
89
  const nv = poChildren(pic).find((c) => poIs(c, "p:nvPicPr"));
90
90
  return { "p:sp": [...nv ? [{ "p:nvSpPr": poChildren(nv) }] : [], { "p:spPr": [{ "a:blipFill": poChildren(blipFill) }, ...poChildren(spPr)] }] };
91
91
  }
92
+ /** Whether a shape properties node has an `a:ln` that states its own fill. */
93
+ function statesLineFill(spPr) {
94
+ const ln = poChildren(spPr).find((c) => poIs(c, "a:ln"));
95
+ return ln !== void 0 && poChildren(ln).some((c) => poIs(c, "a:noFill") || poIs(c, "a:solidFill") || poIs(c, "a:gradFill") || poIs(c, "a:pattFill"));
96
+ }
97
+ /** A line's stated properties, ready to spread over the ones it inherits. */
98
+ function definedProps(line) {
99
+ return Object.fromEntries(Object.entries(line).filter(([, v]) => v !== void 0));
100
+ }
92
101
  /**
93
102
  * Whether a shape is a placeholder — `p:ph` in its OWN non-visual properties.
94
103
  * Read as "anywhere below", a group holding one would take the whole group
@@ -169,12 +178,18 @@ function parseSp(sp, ctx, transform) {
169
178
  const styled = withStatedDirection(resolved, spPr);
170
179
  const lineFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:ln")));
171
180
  let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
172
- if (style) {
173
- const fromStyle = styleRefLine(style, colors, ctx.themeLineWidths);
174
- if (fromStyle) line = line ? {
175
- ...fromStyle,
176
- ...Object.fromEntries(Object.entries(line).filter(([, v]) => v !== void 0))
177
- } : fromStyle;
181
+ const fromStyle = style ? styleRefLine(style, colors, ctx.themeLineWidths) : void 0;
182
+ if (fromStyle) line = line ? {
183
+ ...fromStyle,
184
+ ...definedProps(line)
185
+ } : fromStyle;
186
+ else if (line && lineFrom && !statesLineFill(lineFrom)) {
187
+ const lentLine = protos.find(statesLineFill);
188
+ const lentProps = lentLine ? parseLine(lentLine, colors) : void 0;
189
+ line = lentProps ? {
190
+ ...lentProps,
191
+ ...definedProps(line)
192
+ } : void 0;
178
193
  }
179
194
  const shadowFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:effectLst")));
180
195
  const shadow = shadowFrom ? parseShadow(shadowFrom, colors) : void 0;
@@ -31,8 +31,9 @@ export declare function parsePh(sp: PoNode): PlaceholderRef | undefined;
31
31
  /**
32
32
  * An xfrm node (`a:off` + `a:ext` children) → the EMU box. Works for both
33
33
  * `a:xfrm` (in `p:spPr`) and `p:xfrm` (on a `p:graphicFrame`), whose children are
34
- * identical. Returns `undefined` for a missing or degenerate (non-positive)
35
- * extent.
34
+ * identical. Returns `undefined` for a missing or negative extent, or one that is
35
+ * empty both ways. A single zero is a real box: a horizontal line has `cy="0"` and
36
+ * a vertical one `cx="0"`.
36
37
  */
37
38
  export declare function boxFromXfrm(xfrm: PoNode | undefined): ShapeBoxEmu | undefined;
38
39
  /**
@@ -34,8 +34,9 @@ function parsePh(sp) {
34
34
  /**
35
35
  * An xfrm node (`a:off` + `a:ext` children) → the EMU box. Works for both
36
36
  * `a:xfrm` (in `p:spPr`) and `p:xfrm` (on a `p:graphicFrame`), whose children are
37
- * identical. Returns `undefined` for a missing or degenerate (non-positive)
38
- * extent.
37
+ * identical. Returns `undefined` for a missing or negative extent, or one that is
38
+ * empty both ways. A single zero is a real box: a horizontal line has `cy="0"` and
39
+ * a vertical one `cx="0"`.
39
40
  */
40
41
  function boxFromXfrm(xfrm) {
41
42
  if (!xfrm) return void 0;
@@ -43,7 +44,8 @@ function boxFromXfrm(xfrm) {
43
44
  const ext = poChildren(xfrm).find((c) => poIs(c, "a:ext"));
44
45
  const cx = ext ? poIntAttr(ext, "cx") : void 0;
45
46
  const cy = ext ? poIntAttr(ext, "cy") : void 0;
46
- if (cx === void 0 || cy === void 0 || cx <= 0 || cy <= 0) return void 0;
47
+ if (cx === void 0 || cy === void 0 || cx < 0 || cy < 0) return void 0;
48
+ if (cx === 0 && cy === 0) return void 0;
47
49
  return {
48
50
  x: (off ? poIntAttr(off, "x") : void 0) ?? 0,
49
51
  y: (off ? poIntAttr(off, "y") : void 0) ?? 0,
@@ -83,7 +85,10 @@ function rPrToRunProps(rPr, colors, themeFonts) {
83
85
  ...u !== void 0 ? { underline: u === "none" ? "none" : "single" } : {},
84
86
  ...sz !== void 0 ? { fontSizePt: pt(sz / 100) } : {},
85
87
  ...colorHex ? { colorHex } : {},
86
- ...typeface ? { fontFamily: { ascii: typeface } } : {},
88
+ ...typeface ? { fontFamily: {
89
+ ascii: typeface,
90
+ hAnsi: typeface
91
+ } } : {},
87
92
  ...capsOf(poAttr(rPr, "cap"))
88
93
  };
89
94
  }
@@ -1,7 +1,7 @@
1
1
  import { svgPathData } from "../core/vector.js";
2
2
  import { reverseByCodePoint } from "../core/bidi/index.js";
3
3
  import { FAUX_ITALIC_SHEAR, computeJustifyExtra, lineVisualOrder } from "../layout/line-paint.js";
4
- import { warpGlyphMatrix } from "../core/drawingml/text-warp.js";
4
+ import { warpGlyphMatrix, warpGlyphRun } from "../core/drawingml/text-warp.js";
5
5
  import { sanitizeHref } from "../core/links.js";
6
6
  import { cffOutlineSource, openTypeCff } from "../pdf-reader/cff-outline.js";
7
7
  import { outlineSource } from "../pdf-reader/glyf-outline.js";
@@ -128,10 +128,16 @@ function emitTextToken(out, tok, x, baseline, ctx) {
128
128
  const scale = (tok.synthetic?.widthScale ?? 1) * (tok.resolvedRun.widthScale ?? 1);
129
129
  const slant = tok.synthetic?.italic === true ? FAUX_ITALIC_SHEAR : 0;
130
130
  const rise = tok.risePt ?? 0;
131
- const text = tok.bidiLevel % 2 === 1 ? reverseByCodePoint(tok.text) : tok.text;
131
+ const reversed = tok.bidiLevel % 2 === 1;
132
+ const text = reversed ? reverseByCodePoint(tok.text) : tok.text;
132
133
  const run = tok.font.measure.glyphRun(text);
133
134
  const upem = tok.font.parsed.unitsPerEm;
134
135
  const spacingEm = (tok.resolvedRun.letterSpacingPt ?? 0) / (size * scale);
136
+ const outline = tok.resolvedRun.textOutline;
137
+ const strokeWidth = outline !== void 0 ? outline.widthPt : tok.synthetic?.bold === true ? size * .03 : 0;
138
+ const colours = reversed ? tok.charColorsHex?.slice().reverse() : tok.charColorsHex;
139
+ const sources = colours ? tok.font.measure.glyphSources(text) : void 0;
140
+ const paint = (hex) => hex === void 0 || hex === tok.resolvedRun.colorHex ? "" : ` fill="#${hex}"${strokeWidth > 0 && outline === void 0 ? ` stroke="#${hex}"` : ""}`;
135
141
  const uses = [];
136
142
  let pen = 0;
137
143
  for (let g = 0; g < run.gids.length; g++) {
@@ -140,12 +146,16 @@ function emitTextToken(out, tok, x, baseline, ctx) {
140
146
  emitAsText(out, tok, x, baseline);
141
147
  return;
142
148
  }
143
- if (id !== null) uses.push(`<use href="#${id}"${pen !== 0 ? ` x="${fmtEm(pen)}"` : ""}/>`);
144
- pen += (run.advances[g] ?? 0) / upem + spacingEm;
149
+ const gx = pen + (run.xOffsets?.[g] ?? 0) / upem;
150
+ const gy = (run.yOffsets?.[g] ?? 0) / upem;
151
+ if (id !== null) {
152
+ const fill = paint(sources ? colours?.[sources[g]] : void 0);
153
+ uses.push(`<use href="#${id}"${gx !== 0 ? ` x="${fmtEm(gx)}"` : ""}${gy !== 0 ? ` y="${fmtEm(gy)}"` : ""}${fill}/>`);
154
+ }
155
+ const spaced = run.clusterEnds ? run.clusterEnds[g] === true : true;
156
+ pen += (run.advances[g] ?? 0) / upem + (spaced ? spacingEm : 0);
145
157
  }
146
158
  if (uses.length === 0) return;
147
- const outline = tok.resolvedRun.textOutline;
148
- const strokeWidth = outline !== void 0 ? outline.widthPt : tok.synthetic?.bold === true ? size * .03 : 0;
149
159
  const stroke = strokeWidth > 0 ? ` stroke="#${outline?.colorHex ?? tok.resolvedRun.colorHex}" stroke-width="${fmtEm(strokeWidth / size)}"` : "";
150
160
  const group = `<g transform="matrix(${fmt(size * scale)} 0 ${fmt(slant * size)} ${fmt(-size)} ${fmt(x)} ${fmt(baseline - rise)})" fill="#${tok.resolvedRun.colorHex}"${stroke}>${uses.join("")}</g>`;
151
161
  const href = tok.href !== void 0 ? sanitizeHref(tok.href) : void 0;
@@ -282,6 +292,19 @@ function emitWarped(out, item, ctx) {
282
292
  continue;
283
293
  }
284
294
  const size = tok.fontSizePt;
295
+ const group = (m, uses, hex = tok.resolvedRun.colorHex) => `<g transform="matrix(${fmt(m[0] * size)} ${fmt(m[1] * size)} ${fmt(m[2] * size)} ${fmt(m[3] * size)} ${fmt(m[4])} ${fmt(m[5])})" fill="#${hex}">${uses}</g>`;
296
+ if (tok.font.measure.clustered(tok.text)) {
297
+ const glyphs = warpGlyphRun(warp, tok.font.measure.glyphRun(tok.text), cursor, tok.widthPt, size / tok.font.parsed.unitsPerEm, item.baselineY);
298
+ const colours = tok.charColorsHex;
299
+ const sources = colours ? tok.font.measure.glyphSources(tok.text) : void 0;
300
+ for (const g of glyphs) {
301
+ const id = ctx.glyphs.use(tok.font, g.gid);
302
+ const hex = sources ? colours?.[sources[g.index]] : void 0;
303
+ if (id) out.push(group(g.matrix, `<use href="#${id}"/>`, hex));
304
+ }
305
+ cursor += tok.widthPt;
306
+ continue;
307
+ }
285
308
  const chars = [...tok.text];
286
309
  const raw = chars.map((c) => tok.font.measure.textWidthPt(c, size));
287
310
  const total = raw.reduce((a, b) => a + b, 0);
@@ -301,7 +324,7 @@ function emitWarped(out, item, ctx) {
301
324
  pen += (run.advances[g] ?? 0) / upem;
302
325
  }
303
326
  if (uses.length === 0) continue;
304
- out.push(`<g transform="matrix(${fmt(m[0] * size)} ${fmt(m[1] * size)} ${fmt(m[2] * size)} ${fmt(m[3] * size)} ${fmt(m[4])} ${fmt(m[5])})" fill="#${tok.resolvedRun.colorHex}">${uses.join("")}</g>`);
327
+ out.push(group(m, uses.join("")));
305
328
  }
306
329
  }
307
330
  }
@@ -27,6 +27,11 @@ var TABLE_BORDERS = {
27
27
  insideH: TABLE_BORDER,
28
28
  insideV: TABLE_BORDER
29
29
  };
30
+ var LVL_FOLLOW = [
31
+ " ",
32
+ " ",
33
+ ""
34
+ ];
30
35
  function createListMarkers(tables) {
31
36
  const counters = /* @__PURE__ */ new Map();
32
37
  const resolve = (ilfo, ilvl) => {
@@ -43,7 +48,8 @@ function createListMarkers(tables) {
43
48
  const r = resolve(ilfo, ilvl);
44
49
  if (!r) return void 0;
45
50
  const { lsid, lvl } = r;
46
- if (lvl.nfc === 23 || lvl.nfc === 255 || !lvl.xst.some((cu) => cu <= 8)) return lvl.xst.map((cu) => String.fromCharCode(cu)).join("");
51
+ const follow = LVL_FOLLOW[lvl.follow] ?? " ";
52
+ if (lvl.nfc === 23 || lvl.nfc === 255 || !lvl.xst.some((cu) => cu <= 8)) return lvl.xst.map((cu) => String.fromCharCode(cu)).join("") + follow;
47
53
  const col = counters.get(lsid) ?? [];
48
54
  col[ilvl] = (col[ilvl] ?? lvl.iStartAt - 1) + 1;
49
55
  for (let l = ilvl + 1; l < col.length; l++) col[l] = void 0;
@@ -53,7 +59,7 @@ function createListMarkers(tables) {
53
59
  const other = resolve(ilfo, cu);
54
60
  out += formatListNumber(other?.lvl.nfc ?? 0, col[cu] ?? other?.lvl.iStartAt ?? 1);
55
61
  } else out += String.fromCharCode(cu);
56
- return out;
62
+ return out + follow;
57
63
  } };
58
64
  }
59
65
  function formatListNumber(nfc, n) {
@@ -128,54 +134,79 @@ var DOC_ENCRYPTED_LOSS = {
128
134
  function readDoc(bytes) {
129
135
  const content = extractDocContent(bytes);
130
136
  const resources = new ResourceStore();
131
- const body = buildBody(content, resources);
137
+ const { body, sectionEnds } = buildBody(content, resources);
132
138
  const headersFooters = /* @__PURE__ */ new Map();
133
- const headers = [];
134
- const footers = [];
135
- const addStory = (story, kind, type) => {
136
- if (!story) return;
137
- const id = `${kind}-${type}`;
138
- const els = resolveBodyStyles(story.flatMap((p) => mapParagraph(p, resources)), EMPTY_STYLE_SHEET);
139
- headersFooters.set(id, els);
140
- (kind === "header" ? headers : footers).push({
141
- type,
142
- relationshipId: id
143
- });
139
+ const bandIds = /* @__PURE__ */ new Map();
140
+ const bands = (index) => {
141
+ const headers = [];
142
+ const footers = [];
143
+ const hf = content.headerFooters?.[index];
144
+ const add = (story, kind, type) => {
145
+ if (!story) return;
146
+ let id = bandIds.get(story);
147
+ if (id === void 0) {
148
+ id = `${kind}-${type}-${index}`;
149
+ bandIds.set(story, id);
150
+ headersFooters.set(id, resolveBodyStyles(story.flatMap((p) => mapParagraph(p, resources)), EMPTY_STYLE_SHEET));
151
+ }
152
+ (kind === "header" ? headers : footers).push({
153
+ type,
154
+ relationshipId: id
155
+ });
156
+ };
157
+ add(hf?.defaultHeader, "header", "default");
158
+ add(hf?.firstHeader, "header", "first");
159
+ add(hf?.evenHeader, "header", "even");
160
+ add(hf?.defaultFooter, "footer", "default");
161
+ add(hf?.firstFooter, "footer", "first");
162
+ add(hf?.evenFooter, "footer", "even");
163
+ return {
164
+ headers,
165
+ footers
166
+ };
144
167
  };
145
- const hf = content.headerFooters;
146
- if (hf) {
147
- addStory(hf.defaultHeader, "header", "default");
148
- addStory(hf.firstHeader, "header", "first");
149
- addStory(hf.evenHeader, "header", "even");
150
- addStory(hf.defaultFooter, "footer", "default");
151
- addStory(hf.firstFooter, "footer", "first");
152
- addStory(hf.evenFooter, "footer", "even");
153
- }
154
- const ps = content.pageSize;
155
- const pageSize = ps ? {
156
- width: pt(ps.widthPt),
157
- height: pt(ps.heightPt),
158
- orientation: ps.widthPt > ps.heightPt ? "landscape" : "portrait"
159
- } : {
160
- width: pt(612),
161
- height: pt(792)
168
+ const sectionProperties = (sec, index) => {
169
+ const ps = sec?.pageSize;
170
+ const sectionStart = sec?.bkc !== void 0 ? sectionStartOf(sec.bkc) : void 0;
171
+ const pageNumberFormat = sec?.pageNumberNfc !== void 0 ? pageNumberFormatOf(sec.pageNumberNfc) : void 0;
172
+ return {
173
+ pageSize: ps ? {
174
+ width: pt(ps.widthPt),
175
+ height: pt(ps.heightPt),
176
+ orientation: ps.widthPt > ps.heightPt ? "landscape" : "portrait"
177
+ } : {
178
+ width: pt(612),
179
+ height: pt(792)
180
+ },
181
+ margins: toMargins(sec?.margins),
182
+ ...bands(index),
183
+ ...sec?.titlePage ? { titlePg: true } : {},
184
+ ...content.facingPages ? { evenAndOddHeaders: true } : {},
185
+ ...sectionStart ? { sectionStart } : {},
186
+ ...sec?.pageNumberStart !== void 0 ? { pageNumberStart: sec.pageNumberStart } : {},
187
+ ...pageNumberFormat ? { pageNumberFormat } : {}
188
+ };
162
189
  };
190
+ const docSections = content.sections ?? [];
191
+ const sections = [];
192
+ for (const end of sectionEnds) {
193
+ const last = sections[sections.length - 1]?.endIndex ?? 0;
194
+ if (end.endIndex <= last || end.endIndex >= body.length) continue;
195
+ sections.push({
196
+ properties: sectionProperties(docSections[end.section], end.section),
197
+ endIndex: end.endIndex
198
+ });
199
+ }
200
+ if (sections.length > 0) sections.push({
201
+ properties: sectionProperties(docSections[docSections.length - 1], docSections.length - 1),
202
+ endIndex: body.length
203
+ });
163
204
  return {
164
205
  doc: {
165
206
  kind: "flow",
166
207
  body: resolveBodyStyles(body, EMPTY_STYLE_SHEET),
167
- sections: [],
168
- section: {
169
- pageSize,
170
- margins: {
171
- top: pt(72),
172
- right: pt(72),
173
- bottom: pt(72),
174
- left: pt(72)
175
- },
176
- headers,
177
- footers
178
- },
208
+ sections,
209
+ section: sectionProperties(docSections[0], 0),
179
210
  styles: EMPTY_STYLE_SHEET,
180
211
  resources,
181
212
  ...headersFooters.size > 0 ? { headersFooters } : {},
@@ -186,12 +217,16 @@ function readDoc(bytes) {
186
217
  }
187
218
  function buildBody(content, resources) {
188
219
  const markers = createListMarkers(content.listTables);
189
- const body = groupTables(content.paragraphs, resources, markers);
220
+ const sectionEnds = [];
221
+ const body = groupTables(content.paragraphs, resources, markers, sectionEnds);
190
222
  while (body.length > 1 && isEmptyParagraph(body[body.length - 1])) body.pop();
191
223
  if (body.length === 0) body.push(emptyParagraph());
192
- return body;
224
+ return {
225
+ body,
226
+ sectionEnds
227
+ };
193
228
  }
194
- function groupTables(paras, resources, markers) {
229
+ function groupTables(paras, resources, markers, sectionEnds) {
195
230
  const out = [];
196
231
  let i = 0;
197
232
  while (i < paras.length) if (paras[i].props.inTable) {
@@ -201,7 +236,14 @@ function groupTables(paras, resources, markers) {
201
236
  kind: "table",
202
237
  table: buildTable(group, resources, markers)
203
238
  });
204
- } else out.push(...mapParagraph(paras[i++], resources, markers));
239
+ } else {
240
+ const p = paras[i++];
241
+ out.push(...mapParagraph(p, resources, markers));
242
+ if (p.sectionEnd !== void 0) sectionEnds.push({
243
+ section: p.sectionEnd,
244
+ endIndex: out.length
245
+ });
246
+ }
205
247
  return out;
206
248
  }
207
249
  function buildTable(group, resources, markers) {
@@ -331,16 +373,24 @@ function mapParagraph(p, resources, markers) {
331
373
  const textRuns = p.runs.filter((r) => r.picture === void 0);
332
374
  const ilvl = p.props.listIlvl ?? 0;
333
375
  const isList = (p.props.listIlfo ?? 0) > 0;
334
- if (textRuns.some((r) => r.text.length > 0) || isList) {
376
+ if (textRuns.some((r) => r.text.length > 0 || r.pageBreak || r.field) || isList) {
335
377
  const runs = textRuns.map((r) => ({
336
378
  text: r.text,
337
- properties: toRunProperties(r.props)
379
+ properties: toRunProperties(r.props),
380
+ ...r.pageBreak ? { pageBreak: true } : {},
381
+ ...r.columnBreak ? { columnBreak: true } : {},
382
+ ...r.field ? { field: r.field } : {}
338
383
  }));
384
+ const last = textRuns[textRuns.length - 1];
385
+ if (last?.pageBreak || last?.columnBreak) runs.push({
386
+ text: ZERO_WIDTH_SPACE,
387
+ properties: p.mark ? toRunProperties(p.mark) : {}
388
+ });
339
389
  let properties = toParaProperties(p.props);
340
390
  if (isList) {
341
- const marker = markers?.marker(p.props.listIlfo, ilvl) ?? LIST_BULLETS[ilvl % LIST_BULLETS.length];
391
+ const marker = markers?.marker(p.props.listIlfo, ilvl) ?? `${LIST_BULLETS[ilvl % LIST_BULLETS.length]} `;
342
392
  runs.unshift({
343
- text: `${marker} `,
393
+ text: marker,
344
394
  properties: {}
345
395
  });
346
396
  properties = {
@@ -360,7 +410,7 @@ function mapParagraph(p, resources, markers) {
360
410
  });
361
411
  }
362
412
  for (const r of p.runs) if (r.picture) out.push(imageBlock(r.picture, resources, toParaProperties(p.props)));
363
- if (out.length === 0) out.push(emptyParagraph());
413
+ if (out.length === 0) out.push(emptyParagraph(toParaProperties(p.props), p.mark));
364
414
  return out;
365
415
  }
366
416
  function imageBlock(pic, resources, paragraphProperties) {
@@ -374,14 +424,14 @@ function imageBlock(pic, resources, paragraphProperties) {
374
424
  }
375
425
  };
376
426
  }
377
- function emptyParagraph() {
427
+ function emptyParagraph(properties = {}, mark = void 0) {
378
428
  return {
379
429
  kind: "paragraph",
380
430
  paragraph: {
381
- properties: {},
431
+ properties,
382
432
  runs: [{
383
433
  text: ZERO_WIDTH_SPACE,
384
- properties: {}
434
+ properties: mark ? toRunProperties(mark) : {}
385
435
  }]
386
436
  }
387
437
  };
@@ -392,13 +442,24 @@ function isEmptyParagraph(el) {
392
442
  function toRunProperties(p) {
393
443
  const underline = p.underlineKul ? underlineStyle(p.underlineKul) : void 0;
394
444
  const size = p.sizeHalfPts && p.sizeHalfPts > 0 ? pt(p.sizeHalfPts / 2) : void 0;
445
+ const fontFamily = toFontFamily(p);
395
446
  return {
396
447
  ...p.bold ? { bold: true } : {},
397
448
  ...p.italic ? { italic: true } : {},
398
449
  ...underline ? { underline } : {},
399
- ...size ? { fontSizePt: size } : {}
450
+ ...size ? { fontSizePt: size } : {},
451
+ ...fontFamily ? { fontFamily } : {}
400
452
  };
401
453
  }
454
+ function toFontFamily(p) {
455
+ const fonts = {
456
+ ...p.fontAscii ? { ascii: p.fontAscii } : {},
457
+ ...p.fontOther ? { hAnsi: p.fontOther } : {},
458
+ ...p.fontEastAsia ? { eastAsia: p.fontEastAsia } : {},
459
+ ...p.fontBi ? { cs: p.fontBi } : {}
460
+ };
461
+ return Object.keys(fonts).length > 0 ? fonts : void 0;
462
+ }
402
463
  function toParaProperties(p) {
403
464
  const alignment = p.jc !== void 0 ? alignmentFromJc(p.jc) : void 0;
404
465
  return {
@@ -410,7 +471,8 @@ function toParaProperties(p) {
410
471
  ...p.spaceAfterTwips !== void 0 ? { spacingAfter: pt(p.spaceAfterTwips / 20) } : {},
411
472
  ...p.widowControl !== void 0 ? { widowControl: p.widowControl } : {},
412
473
  ...p.keepNext !== void 0 ? { keepNext: p.keepNext } : {},
413
- ...p.keepLines !== void 0 ? { keepLines: p.keepLines } : {}
474
+ ...p.keepLines !== void 0 ? { keepLines: p.keepLines } : {},
475
+ ...p.pageBreakBefore !== void 0 ? { pageBreakBefore: p.pageBreakBefore } : {}
414
476
  };
415
477
  }
416
478
  function underlineStyle(kul) {
@@ -422,6 +484,35 @@ function underlineStyle(kul) {
422
484
  default: return "single";
423
485
  }
424
486
  }
487
+ function toMargins(m) {
488
+ const side = (twips) => twipsToPt(twips ?? 1440);
489
+ return {
490
+ top: side(m?.topTwips),
491
+ right: side(m?.rightTwips),
492
+ bottom: side(m?.bottomTwips),
493
+ left: side(m?.leftTwips),
494
+ ...m?.headerTwips !== void 0 ? { header: twipsToPt(m.headerTwips) } : {},
495
+ ...m?.footerTwips !== void 0 ? { footer: twipsToPt(m.footerTwips) } : {},
496
+ ...m?.gutterTwips ? { gutter: twipsToPt(m.gutterTwips) } : {}
497
+ };
498
+ }
499
+ function sectionStartOf(bkc) {
500
+ switch (bkc) {
501
+ case 0: return "continuous";
502
+ case 3: return "evenPage";
503
+ case 4: return "oddPage";
504
+ default: return "nextPage";
505
+ }
506
+ }
507
+ function pageNumberFormatOf(nfc) {
508
+ switch (nfc) {
509
+ case 1: return "upperRoman";
510
+ case 2: return "lowerRoman";
511
+ case 3: return "upperLetter";
512
+ case 4: return "lowerLetter";
513
+ default: return;
514
+ }
515
+ }
425
516
  function alignmentFromJc(jc) {
426
517
  switch (jc) {
427
518
  case 1: return "center";