reamkit 1.0.2 → 1.2.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 (53) hide show
  1. package/README.md +12 -6
  2. package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
  3. package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
  4. package/dist/esm/core/bytes.d.ts +1 -0
  5. package/dist/esm/core/bytes.js +6 -1
  6. package/dist/esm/core/converter/facade.d.ts +2 -2
  7. package/dist/esm/core/converter/facade.js +12 -0
  8. package/dist/esm/core/converter/project.js +2 -0
  9. package/dist/esm/core/converter/ream.d.ts +1 -1
  10. package/dist/esm/core/converter/ream.js +10 -0
  11. package/dist/esm/core/document-model/index.d.ts +1 -1
  12. package/dist/esm/core/document-model/types.d.ts +58 -0
  13. package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +1 -1
  14. package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
  15. package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
  16. package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
  17. package/dist/esm/core/drawingml/shape-render.js +71 -0
  18. package/dist/esm/core/ir/features.d.ts +1 -0
  19. package/dist/esm/core/ir/features.js +1 -0
  20. package/dist/esm/core/ir/flow.d.ts +3 -0
  21. package/dist/esm/core/links.d.ts +6 -0
  22. package/dist/esm/core/links.js +19 -0
  23. package/dist/esm/core/numbering/apply.js +3 -1
  24. package/dist/esm/core/style-cascade/index.d.ts +1 -0
  25. package/dist/esm/core/style-cascade/index.js +1 -0
  26. package/dist/esm/core/style-cascade/table.d.ts +2 -0
  27. package/dist/esm/core/style-cascade/table.js +161 -0
  28. package/dist/esm/core/vector.d.ts +2 -0
  29. package/dist/esm/core/vector.js +19 -1
  30. package/dist/esm/html/html-writer.d.ts +4 -0
  31. package/dist/esm/html/html-writer.js +464 -0
  32. package/dist/esm/index.d.ts +1 -0
  33. package/dist/esm/index.js +2 -1
  34. package/dist/esm/layout/page-doc.d.ts +3 -0
  35. package/dist/esm/layout/styled-layout.d.ts +19 -3
  36. package/dist/esm/layout/styled-layout.js +533 -197
  37. package/dist/esm/pdf/struct-tree.d.ts +7 -1
  38. package/dist/esm/pdf/struct-tree.js +22 -6
  39. package/dist/esm/pdf/styled-page-emitter.d.ts +1 -1
  40. package/dist/esm/pdf/styled-page-emitter.js +161 -29
  41. package/dist/esm/pdf/xmp.d.ts +1 -0
  42. package/dist/esm/pdf/xmp.js +4 -0
  43. package/dist/esm/svg/svg-writer.js +3 -11
  44. package/dist/esm/word/document-parser.d.ts +3 -0
  45. package/dist/esm/word/document-parser.js +210 -23
  46. package/dist/esm/word/docx-reader.js +30 -4
  47. package/dist/esm/word/drawing-parser.d.ts +4 -1
  48. package/dist/esm/word/drawing-parser.js +53 -2
  49. package/dist/esm/word/index.d.ts +2 -2
  50. package/dist/esm/word/styles-parser.js +134 -1
  51. package/dist/esm/word/table-parser.js +35 -0
  52. package/package.json +1 -1
  53. /package/dist/esm/{layout → core/drawingml}/chart-geometry.js +0 -0
@@ -78,6 +78,7 @@ function parseSectPrNode(sectPr) {
78
78
  let pageSize;
79
79
  let margins;
80
80
  let titlePg = false;
81
+ let columns;
81
82
  const headers = [];
82
83
  const footers = [];
83
84
  for (const child of poChildren(sectPr)) if (poIs(child, "w:pgSz")) {
@@ -109,13 +110,34 @@ function parseSectPrNode(sectPr) {
109
110
  else if (poIs(child, "w:titlePg")) {
110
111
  const val = poAttr(child, "val");
111
112
  titlePg = val === void 0 || val === "" || val !== "0" && val !== "false";
112
- }
113
+ } else if (poIs(child, "w:cols")) columns = parseColumns(child);
113
114
  return {
114
115
  ...pageSize ? { pageSize } : {},
115
116
  ...margins ? { margins } : {},
116
117
  headers,
117
118
  footers,
118
- ...titlePg ? { titlePg: true } : {}
119
+ ...titlePg ? { titlePg: true } : {},
120
+ ...columns ? { columns } : {}
121
+ };
122
+ }
123
+ function parseColumns(cols) {
124
+ const explicit = [];
125
+ for (const col of poChildren(cols)) {
126
+ if (!poIs(col, "w:col")) continue;
127
+ const w = poIntAttr(col, "w");
128
+ if (w === void 0) continue;
129
+ explicit.push({
130
+ widthPt: twipsToPt(w),
131
+ spacePt: twipsToPt(poIntAttr(col, "space") ?? 0)
132
+ });
133
+ }
134
+ const num = poIntAttr(cols, "num");
135
+ const count = explicit.length > 0 ? explicit.length : num ?? 1;
136
+ if (count <= 1) return void 0;
137
+ return {
138
+ count,
139
+ spacePt: twipsToPt(poIntAttr(cols, "space") ?? 720),
140
+ ...explicit.length > 0 ? { explicit } : {}
119
141
  };
120
142
  }
121
143
  function pushHeaderFooter(node, list) {
@@ -135,12 +157,17 @@ function parseHeaderFooter(xml, ctx = DEFAULT_PARSE_CONTEXT) {
135
157
  }
136
158
  function parseBodyElements(children, ctx = DEFAULT_PARSE_CONTEXT) {
137
159
  const out = [];
138
- for (const child of children) if (poIs(child, "w:p")) {
160
+ let pendingBookmarks;
161
+ for (const child of children) if (poIs(child, "w:bookmarkStart")) {
162
+ const bookmarkName = poAttr(child, "name");
163
+ if (bookmarkName !== void 0 && bookmarkName !== "" && bookmarkName !== "_GoBack") (pendingBookmarks ??= []).push(bookmarkName);
164
+ } else if (poIs(child, "w:p")) {
139
165
  const drawing = tryExtractDrawingFromParagraph(child, ctx);
140
166
  out.push(drawing ?? {
141
167
  kind: "paragraph",
142
- paragraph: parseParagraph(child, ctx)
168
+ paragraph: parseParagraph(child, ctx, pendingBookmarks)
143
169
  });
170
+ if (!drawing) pendingBookmarks = void 0;
144
171
  } else if (poIs(child, "w:tbl")) out.push({
145
172
  kind: "table",
146
173
  table: parseTable(child, ctx)
@@ -172,7 +199,8 @@ function tryExtractDrawingFromParagraph(p, ctx) {
172
199
  width: content.width,
173
200
  height: content.height,
174
201
  paragraphProperties,
175
- ...content.altText ? { altText: content.altText } : {}
202
+ ...content.altText ? { altText: content.altText } : {},
203
+ ...content.float ? { float: content.float } : {}
176
204
  }
177
205
  };
178
206
  }
@@ -183,7 +211,8 @@ function tryExtractDrawingFromParagraph(p, ctx) {
183
211
  width: content.width,
184
212
  height: content.height,
185
213
  paragraphProperties,
186
- ...content.altText ? { altText: content.altText } : {}
214
+ ...content.altText ? { altText: content.altText } : {},
215
+ ...content.float ? { float: content.float } : {}
187
216
  }
188
217
  };
189
218
  return {
@@ -191,11 +220,18 @@ function tryExtractDrawingFromParagraph(p, ctx) {
191
220
  shape: {
192
221
  ...content.data,
193
222
  paragraphProperties,
194
- ...content.altText ? { altText: content.altText } : {}
223
+ ...content.altText ? { altText: content.altText } : {},
224
+ ...content.float ? { float: content.float } : {}
195
225
  }
196
226
  };
197
227
  }
198
- function parseParagraph(p, ctx) {
228
+ function parseParagraph(p, ctx, extraBookmarks) {
229
+ const bookmarks = [...extraBookmarks ?? []];
230
+ for (const child of poChildren(p)) {
231
+ if (!poIs(child, "w:bookmarkStart")) continue;
232
+ const bookmarkName = poAttr(child, "name");
233
+ if (bookmarkName !== void 0 && bookmarkName !== "" && bookmarkName !== "_GoBack") bookmarks.push(bookmarkName);
234
+ }
199
235
  const pPr = poChildren(p).find((c) => poIs(c, "w:pPr"));
200
236
  let properties = parseParagraphProperties(pPr ? poElementToFlat(pPr) : void 0);
201
237
  const mathPara = poChildren(p).find((c) => poIs(c, "m:oMathPara"));
@@ -208,38 +244,139 @@ function parseParagraph(p, ctx) {
208
244
  alignment
209
245
  };
210
246
  }
211
- const runs = [];
212
- collectRuns(p, runs, ctx);
247
+ const collected = [];
248
+ collectRuns(p, collected, ctx);
213
249
  return {
214
250
  properties,
215
- runs
251
+ runs: applyFieldFsm(collected),
252
+ ...bookmarks.length > 0 ? { bookmarks } : {}
216
253
  };
217
254
  }
218
- function collectRuns(container, out, ctx) {
255
+ function parseFieldInstr(instr) {
256
+ if (!instr) return void 0;
257
+ const kw = /^\s*([A-Za-z]+)/.exec(instr)?.[1]?.toUpperCase();
258
+ return kw === "PAGE" ? "PAGE" : kw === "NUMPAGES" ? "NUMPAGES" : void 0;
259
+ }
260
+ function synthesizeFieldRun(result, field, href) {
261
+ const first = result[0];
262
+ const linked = href ?? result.find((r) => r.href !== void 0)?.href;
263
+ return {
264
+ text: result.map((r) => r.text).join(""),
265
+ properties: first?.properties ?? {},
266
+ field,
267
+ ...linked !== void 0 ? { href: linked } : {}
268
+ };
269
+ }
270
+ function applyFieldFsm(collected) {
271
+ const out = [];
272
+ let st = null;
273
+ for (const c of collected) {
274
+ if (c.fldChar === "begin") {
275
+ if (st) if (st.phase === "instr") st.depth++;
276
+ else {
277
+ out.push(...st.result);
278
+ st = {
279
+ phase: "instr",
280
+ instr: "",
281
+ result: [],
282
+ depth: 0
283
+ };
284
+ }
285
+ else st = {
286
+ phase: "instr",
287
+ instr: "",
288
+ result: [],
289
+ depth: 0
290
+ };
291
+ continue;
292
+ }
293
+ if (!st) {
294
+ out.push(c.run);
295
+ continue;
296
+ }
297
+ if (c.fldChar === "separate") {
298
+ if (st.depth === 0) st.phase = "result";
299
+ continue;
300
+ }
301
+ if (c.fldChar === "end") {
302
+ if (st.depth > 0) {
303
+ st.depth--;
304
+ continue;
305
+ }
306
+ const field = parseFieldInstr(st.instr);
307
+ if (field) out.push(synthesizeFieldRun(st.result, field));
308
+ else out.push(...st.result);
309
+ st = null;
310
+ continue;
311
+ }
312
+ if (st.phase === "instr") {
313
+ if (c.instrText !== void 0) st.instr += c.instrText;
314
+ continue;
315
+ }
316
+ st.result.push(c.run);
317
+ }
318
+ if (st) out.push(...st.result);
319
+ return out;
320
+ }
321
+ function collectRuns(container, out, ctx, href, anchor) {
219
322
  for (const child of poChildren(container)) {
220
323
  if (poIs(child, "w:pPr")) continue;
221
324
  if (poIs(child, "w:r")) {
222
- out.push(parseRun(child, ctx));
325
+ const parsed = parseRun(child, ctx);
326
+ const run = href !== void 0 || anchor !== void 0 ? {
327
+ ...parsed.run,
328
+ ...href !== void 0 ? { href } : {},
329
+ ...anchor !== void 0 ? { anchor } : {}
330
+ } : parsed.run;
331
+ out.push({
332
+ run,
333
+ ...parsed.fldChar ? { fldChar: parsed.fldChar } : {},
334
+ ...parsed.instrText !== void 0 ? { instrText: parsed.instrText } : {}
335
+ });
223
336
  continue;
224
337
  }
225
338
  if (poIs(child, "m:oMath")) {
226
- out.push({
339
+ out.push({ run: {
227
340
  text: "",
228
341
  properties: {},
229
342
  math: parseOMath(child)
230
- });
343
+ } });
231
344
  continue;
232
345
  }
233
346
  if (poIs(child, "m:oMathPara")) {
234
- for (const om of poChildren(child)) if (poIs(om, "m:oMath")) out.push({
347
+ for (const om of poChildren(child)) if (poIs(om, "m:oMath")) out.push({ run: {
235
348
  text: "",
236
349
  properties: {},
237
350
  math: parseOMath(om)
238
- });
351
+ } });
239
352
  continue;
240
353
  }
241
354
  const tag = elementTag(child);
242
- if (tag && RUN_CONTAINER_TAGS.has(tag)) collectRuns(child, out, ctx);
355
+ if (tag === "w:fldSimple") {
356
+ const field = parseFieldInstr(poAttr(child, "instr"));
357
+ if (field) {
358
+ const inner = [];
359
+ collectRuns(child, inner, ctx, href, anchor);
360
+ out.push({ run: synthesizeFieldRun(applyFieldFsm(inner), field, href) });
361
+ continue;
362
+ }
363
+ collectRuns(child, out, ctx, href, anchor);
364
+ continue;
365
+ }
366
+ if (tag && RUN_CONTAINER_TAGS.has(tag)) {
367
+ let childHref = href;
368
+ let childAnchor = anchor;
369
+ if (tag === "w:hyperlink") {
370
+ const rId = poAttr(child, "id");
371
+ const resolved = rId ? ctx.resolveHyperlink?.(rId) : void 0;
372
+ if (resolved !== void 0) childHref = resolved;
373
+ else {
374
+ const bookmark = poAttr(child, "anchor");
375
+ if (bookmark !== void 0 && bookmark !== "") childAnchor = bookmark;
376
+ }
377
+ }
378
+ collectRuns(child, out, ctx, childHref, childAnchor);
379
+ }
243
380
  }
244
381
  }
245
382
  function parseRun(r, ctx) {
@@ -248,8 +385,36 @@ function parseRun(r, ctx) {
248
385
  let text = "";
249
386
  let pageBreak = false;
250
387
  let inlineImage;
388
+ let fldChar;
389
+ let instrText;
390
+ let footnoteRef;
391
+ let endnoteRef;
392
+ let noteNumber = false;
251
393
  for (const child of expandMcChildren(poChildren(r))) {
252
394
  if (poIs(child, "w:rPr")) continue;
395
+ if (poIs(child, "w:fldChar")) {
396
+ const t = poAttr(child, "fldCharType");
397
+ if (t === "begin" || t === "separate" || t === "end") fldChar = t;
398
+ continue;
399
+ }
400
+ if (poIs(child, "w:instrText")) {
401
+ instrText = (instrText ?? "") + poText(child);
402
+ continue;
403
+ }
404
+ if (poIs(child, "w:footnoteReference")) {
405
+ const id = poAttr(child, "id");
406
+ if (id !== void 0) footnoteRef = id;
407
+ continue;
408
+ }
409
+ if (poIs(child, "w:endnoteReference")) {
410
+ const id = poAttr(child, "id");
411
+ if (id !== void 0) endnoteRef = id;
412
+ continue;
413
+ }
414
+ if (poIs(child, "w:footnoteRef") || poIs(child, "w:endnoteRef")) {
415
+ noteNumber = true;
416
+ continue;
417
+ }
253
418
  if (poIs(child, "w:t")) text += poText(child);
254
419
  else if (poIs(child, "w:tab")) text += " ";
255
420
  else if (poIs(child, "w:br")) if (poAttr(child, "type") === "page") pageBreak = true;
@@ -269,14 +434,36 @@ function parseRun(r, ctx) {
269
434
  }
270
435
  }
271
436
  return {
272
- text,
273
- properties,
274
- ...inlineImage ? { inlineImage } : {},
275
- ...pageBreak ? { pageBreak: true } : {}
437
+ run: {
438
+ text,
439
+ properties,
440
+ ...inlineImage ? { inlineImage } : {},
441
+ ...pageBreak ? { pageBreak: true } : {},
442
+ ...footnoteRef !== void 0 ? { footnoteRef } : {},
443
+ ...endnoteRef !== void 0 ? { endnoteRef } : {},
444
+ ...noteNumber ? { noteNumber: true } : {}
445
+ },
446
+ ...fldChar ? { fldChar } : {},
447
+ ...instrText !== void 0 ? { instrText } : {}
276
448
  };
277
449
  }
278
450
  function elementTag(node) {
279
451
  for (const key of Object.keys(node)) if (key !== ":@" && key !== "#text") return key;
280
452
  }
453
+ function parseNotes(notesXml, rootTag, noteTag, ctx = DEFAULT_PARSE_CONTEXT) {
454
+ const xml = decoder.decode(notesXml);
455
+ const root = poFindByPath(parser.parse(xml), [rootTag]);
456
+ const out = /* @__PURE__ */ new Map();
457
+ if (!root) return out;
458
+ for (const note of poChildren(root)) {
459
+ if (!poIs(note, noteTag)) continue;
460
+ const type = poAttr(note, "type");
461
+ if (type !== void 0 && type !== "normal") continue;
462
+ const id = poAttr(note, "id");
463
+ if (id === void 0) continue;
464
+ out.set(id, parseBodyElements(poChildren(note), ctx));
465
+ }
466
+ return out;
467
+ }
281
468
  //#endregion
282
- export { DEFAULT_PARSE_CONTEXT, EMPTY_SECTION, parseBodyElements, parseDocument, parseHeaderFooter, parseSections };
469
+ export { DEFAULT_PARSE_CONTEXT, EMPTY_SECTION, parseBodyElements, parseDocument, parseHeaderFooter, parseNotes, parseSections };
@@ -2,6 +2,7 @@ import { ResourceStore } from "../core/ir/resources.js";
2
2
  import { FEATURES } from "../core/ir/features.js";
3
3
  import { applyNumbering, applyNumberingToHeadersFooters } from "../core/numbering/apply.js";
4
4
  import { EMPTY_STYLE_SHEET, resolveBodyStyles, resolveHeadersFootersStyles } from "../core/style-cascade/resolver.js";
5
+ import { resolveTableStyles } from "../core/style-cascade/table.js";
5
6
  import "../core/style-cascade/index.js";
6
7
  import { bytesInclude } from "../core/bytes.js";
7
8
  import { DEFAULT_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
@@ -10,7 +11,7 @@ import { parseTheme } from "../core/drawingml/theme-parser.js";
10
11
  import { OpcPackage } from "../core/opc/package.js";
11
12
  import { parseCoreProperties } from "../core/opc/core-properties.js";
12
13
  import "../core/opc/index.js";
13
- import { EMPTY_SECTION, parseDocument, parseHeaderFooter, parseSections } from "./document-parser.js";
14
+ import { EMPTY_SECTION, parseDocument, parseHeaderFooter, parseNotes, parseSections } from "./document-parser.js";
14
15
  import { parseStyles } from "./styles-parser.js";
15
16
  import { loadEmbeddedFonts } from "./font-table.js";
16
17
  import { EMPTY_NUMBERING, parseNumbering } from "./numbering-parser.js";
@@ -18,11 +19,14 @@ import { EMPTY_SETTINGS, parseSettings } from "./settings-parser.js";
18
19
  import "./index.js";
19
20
  //#region src/word/docx-reader.ts
20
21
  var STYLES_PART = "word/styles.xml";
22
+ var FOOTNOTES_PART = "word/footnotes.xml";
23
+ var ENDNOTES_PART = "word/endnotes.xml";
21
24
  var NUMBERING_PART = "word/numbering.xml";
22
25
  var SETTINGS_PART = "word/settings.xml";
23
26
  var CORE_PROPS_PART = "docProps/core.xml";
24
27
  var MAIN_DOCUMENT_PART = "word/document.xml";
25
28
  var REL_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
29
+ var REL_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
26
30
  var REL_CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
27
31
  var REL_THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
28
32
  var REL_HEADER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
@@ -35,7 +39,8 @@ function readDocx(docx) {
35
39
  const resources = new ResourceStore();
36
40
  const ctx = {
37
41
  resolveColor,
38
- resolveImage: makeImageResolver(pkg, resources)
42
+ resolveImage: makeImageResolver(pkg, resources),
43
+ resolveHyperlink: makeHyperlinkResolver(pkg)
39
44
  };
40
45
  const body = parseDocument(main.data, ctx);
41
46
  const rawSections = parseSections(main.data);
@@ -43,6 +48,15 @@ function readDocx(docx) {
43
48
  const styles = stylesData ? parseStyles(stylesData) : EMPTY_STYLE_SHEET;
44
49
  const numberingData = pkg.getPart(NUMBERING_PART);
45
50
  const numbering = numberingData ? parseNumbering(numberingData) : EMPTY_NUMBERING;
51
+ const noteCtx = (part) => ({
52
+ resolveColor,
53
+ resolveImage: makeImageResolver(pkg, resources, part),
54
+ resolveHyperlink: makeHyperlinkResolver(pkg, part)
55
+ });
56
+ const footnotesData = pkg.getPart(FOOTNOTES_PART);
57
+ const rawFootnotes = footnotesData ? parseNotes(footnotesData, "w:footnotes", "w:footnote", noteCtx(FOOTNOTES_PART)) : void 0;
58
+ const endnotesData = pkg.getPart(ENDNOTES_PART);
59
+ const rawEndnotes = endnotesData ? parseNotes(endnotesData, "w:endnotes", "w:endnote", noteCtx(ENDNOTES_PART)) : void 0;
46
60
  const settingsData = pkg.getPart(SETTINGS_PART);
47
61
  const settings = settingsData ? parseSettings(settingsData) : EMPTY_SETTINGS;
48
62
  const sections = rawSections.length > 0 ? rawSections.map((s) => ({
@@ -67,10 +81,12 @@ function readDocx(docx) {
67
81
  return {
68
82
  doc: {
69
83
  kind: "flow",
70
- body: resolveBodyStyles(applyNumbering(body, numbering), styles),
84
+ body: resolveBodyStyles(applyNumbering(resolveTableStyles(body, styles), numbering), styles),
71
85
  sections,
72
86
  styles,
73
87
  numbering,
88
+ ...rawFootnotes && rawFootnotes.size > 0 ? { footnotes: transformNotes(rawFootnotes, styles, numbering) } : {},
89
+ ...rawEndnotes && rawEndnotes.size > 0 ? { endnotes: transformNotes(rawEndnotes, styles, numbering) } : {},
74
90
  headersFooters: resolveHeadersFootersStyles(applyNumberingToHeadersFooters(headersFooters, numbering), styles),
75
91
  charts,
76
92
  resources,
@@ -129,6 +145,15 @@ function makeImageResolver(pkg, store, partName = MAIN_DOCUMENT_PART) {
129
145
  return id;
130
146
  };
131
147
  }
148
+ function transformNotes(notes, styles, numbering) {
149
+ for (const content of notes.values()) resolveTableStyles(content, styles);
150
+ return resolveHeadersFootersStyles(applyNumberingToHeadersFooters(notes, numbering), styles);
151
+ }
152
+ function makeHyperlinkResolver(pkg, partName = MAIN_DOCUMENT_PART) {
153
+ const byRelId = /* @__PURE__ */ new Map();
154
+ for (const rel of pkg.getPartRelationships(partName)) if (rel.type === REL_HYPERLINK && rel.targetMode === "External") byRelId.set(rel.id, rel.target);
155
+ return (relId) => byRelId.get(relId);
156
+ }
132
157
  function loadCharts(pkg, resolveColor) {
133
158
  const out = /* @__PURE__ */ new Map();
134
159
  for (const rel of pkg.getPartRelationships(MAIN_DOCUMENT_PART)) {
@@ -172,7 +197,8 @@ function loadHeadersFootersForSections(pkg, sections, ctx, store) {
172
197
  if (!resolved) continue;
173
198
  const hfCtx = {
174
199
  resolveColor: ctx.resolveColor,
175
- resolveImage: makeImageResolver(pkg, store, resolved.path)
200
+ resolveImage: makeImageResolver(pkg, store, resolved.path),
201
+ resolveHyperlink: makeHyperlinkResolver(pkg, resolved.path)
176
202
  };
177
203
  out.set(rel.id, parseHeaderFooter(resolved.data, hfCtx));
178
204
  }
@@ -1,4 +1,4 @@
1
- import { BodyElement, ShapeFill, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform } from '../core/document-model/index.js';
1
+ import { BodyElement, FloatAnchor, ShapeFill, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
3
  import { PoNode } from '../core/po-helpers.js';
4
4
  import { Pt } from '../core/ir/index.js';
@@ -18,16 +18,19 @@ export type DrawingContent = {
18
18
  readonly width: Pt;
19
19
  readonly height: Pt;
20
20
  readonly altText?: string;
21
+ readonly float?: FloatAnchor;
21
22
  } | {
22
23
  readonly kind: 'shape';
23
24
  readonly data: ShapeData;
24
25
  readonly altText?: string;
26
+ readonly float?: FloatAnchor;
25
27
  } | {
26
28
  readonly kind: 'chart';
27
29
  readonly chartRelId: string;
28
30
  readonly width: Pt;
29
31
  readonly height: Pt;
30
32
  readonly altText?: string;
33
+ readonly float?: FloatAnchor;
31
34
  };
32
35
  export declare function resolveMc(altContent: PoNode): ReadonlyArray<PoNode>;
33
36
  export declare function expandMcChildren(children: ReadonlyArray<PoNode>): Array<PoNode>;
@@ -1,10 +1,57 @@
1
1
  import { emuToPt } from "../core/ir/units.js";
2
- import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag } from "../core/po-helpers.js";
2
+ import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
3
3
  import { resolveColorNode } from "../core/drawingml/colors.js";
4
4
  //#region src/word/drawing-parser.ts
5
5
  var WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
6
6
  var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
7
7
  var UNDERSTOOD_NS = new Set(["wps"]);
8
+ function parseFloatAnchor(anchor) {
9
+ if (!poIs(anchor, "wp:anchor")) return void 0;
10
+ const behindRaw = poAttr(anchor, "behindDoc");
11
+ const behind = behindRaw === "1" || behindRaw === "true";
12
+ let wrap = "none";
13
+ for (const child of poChildren(anchor)) if (poIs(child, "wp:wrapSquare")) wrap = "square";
14
+ else if (poIs(child, "wp:wrapTight")) wrap = "tight";
15
+ else if (poIs(child, "wp:wrapThrough")) wrap = "through";
16
+ else if (poIs(child, "wp:wrapTopAndBottom")) wrap = "topAndBottom";
17
+ const posH = parseAnchorPos(anchor, "wp:positionH", [
18
+ "margin",
19
+ "page",
20
+ "column"
21
+ ]);
22
+ const posV = parseAnchorPos(anchor, "wp:positionV", [
23
+ "margin",
24
+ "page",
25
+ "paragraph",
26
+ "line"
27
+ ]);
28
+ return {
29
+ wrap,
30
+ ...behind ? { behind: true } : {},
31
+ ...posH ? { posH } : {},
32
+ ...posV ? { posV } : {}
33
+ };
34
+ }
35
+ var ANCHOR_ALIGNS = new Set([
36
+ "left",
37
+ "center",
38
+ "right"
39
+ ]);
40
+ function parseAnchorPos(anchor, tag, allowed) {
41
+ const pos = poChildren(anchor).find((c) => poIs(c, tag));
42
+ if (!pos) return void 0;
43
+ const relRaw = poAttr(pos, "relativeFrom") ?? "margin";
44
+ const relativeFrom = allowed.includes(relRaw) ? relRaw : allowed[0];
45
+ const offsetNode = poChildren(pos).find((c) => poIs(c, "wp:posOffset"));
46
+ const offsetRaw = offsetNode ? Number(poText(offsetNode).trim()) : NaN;
47
+ const alignNode = poChildren(pos).find((c) => poIs(c, "wp:align"));
48
+ const alignRaw = alignNode ? poText(alignNode).trim() : "";
49
+ return {
50
+ relativeFrom,
51
+ ...Number.isFinite(offsetRaw) ? { offsetPt: emuToPt(offsetRaw) } : {},
52
+ ...tag === "wp:positionH" && ANCHOR_ALIGNS.has(alignRaw) ? { align: alignRaw } : {}
53
+ };
54
+ }
8
55
  function resolveMc(altContent) {
9
56
  for (const choice of poChildren(altContent)) {
10
57
  if (!poIs(choice, "mc:Choice")) continue;
@@ -30,7 +77,11 @@ function parseDrawing(drawing, resolveColor, parseBody) {
30
77
  const descr = docPr ? poAttr(docPr, "descr") : void 0;
31
78
  const title = docPr ? poAttr(docPr, "title") : void 0;
32
79
  const altText = (descr ?? title)?.trim() || void 0;
33
- const alt = altText ? { altText } : {};
80
+ const float = parseFloatAnchor(anchor);
81
+ const alt = {
82
+ ...altText ? { altText } : {},
83
+ ...float ? { float } : {}
84
+ };
34
85
  const graphicData = poFindDescendant(anchor, "a:graphicData");
35
86
  const uri = graphicData ? poAttr(graphicData, "uri") : void 0;
36
87
  if (graphicData && uri === WPS_URI) {
@@ -1,6 +1,6 @@
1
- export type { ImageResolver, ParseContext } from './document-parser.js';
1
+ export type { HyperlinkResolver, ImageResolver, ParseContext } from './document-parser.js';
2
2
  export { extractParagraphs } from './text-extractor.js';
3
- export { parseDocument, parseBodyElements, parseSection, parseSections, parseHeaderFooter, EMPTY_SECTION, } from './document-parser.js';
3
+ export { parseDocument, parseBodyElements, parseSection, parseSections, parseHeaderFooter, parseNotes, EMPTY_SECTION, } from './document-parser.js';
4
4
  export { parseRunProperties } from './run-properties.js';
5
5
  export { parseParagraphProperties } from './paragraph-properties.js';
6
6
  export { parseStyles } from './styles-parser.js';
@@ -1,3 +1,4 @@
1
+ import { eighthPtToPt, twipsToPt } from "../core/ir/units.js";
1
2
  import { EMPTY_STYLE_SHEET } from "../core/style-cascade/resolver.js";
2
3
  import "../core/style-cascade/index.js";
3
4
  import { asArray, asElement, getAttr, getVal } from "./xml-helpers.js";
@@ -50,7 +51,8 @@ function parseStyles(stylesXml) {
50
51
  ...basedOnVal ? { basedOn: basedOnVal } : {},
51
52
  isDefault,
52
53
  runProperties: parseRunProperties(el["w:rPr"]),
53
- paragraphProperties: parseParagraphProperties(el["w:pPr"])
54
+ paragraphProperties: parseParagraphProperties(el["w:pPr"]),
55
+ ...type === "table" ? parseTableStyleParts(el) : {}
54
56
  };
55
57
  styles.set(id, style);
56
58
  }
@@ -60,5 +62,136 @@ function parseStyles(stylesXml) {
60
62
  styles
61
63
  };
62
64
  }
65
+ var CONDITION_TYPES = new Set([
66
+ "wholeTable",
67
+ "band1Vert",
68
+ "band2Vert",
69
+ "band1Horz",
70
+ "band2Horz",
71
+ "firstCol",
72
+ "lastCol",
73
+ "firstRow",
74
+ "lastRow",
75
+ "nwCell",
76
+ "neCell",
77
+ "swCell",
78
+ "seCell"
79
+ ]);
80
+ function parseTableStyleParts(el) {
81
+ const out = {};
82
+ const base = parseTableStyleLayer(el);
83
+ if (base) out.tableLayer = base;
84
+ const tblPr = asElement(el["w:tblPr"]);
85
+ if (tblPr) {
86
+ const rowBand = intVal(tblPr["w:tblStyleRowBandSize"]);
87
+ const colBand = intVal(tblPr["w:tblStyleColBandSize"]);
88
+ if (rowBand !== void 0 && rowBand > 0) out.rowBandSize = rowBand;
89
+ if (colBand !== void 0 && colBand > 0) out.colBandSize = colBand;
90
+ }
91
+ const conditions = [];
92
+ for (const c of asArray(el["w:tblStylePr"])) {
93
+ const cond = asElement(c);
94
+ if (!cond) continue;
95
+ const typeAttr = getAttr(cond, "type");
96
+ if (!typeAttr || !CONDITION_TYPES.has(typeAttr)) continue;
97
+ const layer = parseTableStyleLayer(cond);
98
+ if (layer) conditions.push({
99
+ type: typeAttr,
100
+ layer
101
+ });
102
+ }
103
+ if (conditions.length > 0) out.tableConditions = conditions;
104
+ return out;
105
+ }
106
+ function parseTableStyleLayer(el) {
107
+ const tblPr = asElement(el["w:tblPr"]);
108
+ const tcPr = asElement(el["w:tcPr"]);
109
+ const borders = parseFlatBorders(tblPr ? asElement(tblPr["w:tblBorders"]) : void 0) ?? parseFlatBorders(tcPr ? asElement(tcPr["w:tcBorders"]) : void 0);
110
+ const cellMargins = parseFlatCellMargins(tblPr ? asElement(tblPr["w:tblCellMar"]) : void 0);
111
+ const shading = parseFlatShading(tcPr ? tcPr["w:shd"] : void 0);
112
+ const runProperties = parseRunProperties(el["w:rPr"]);
113
+ const paragraphProperties = parseParagraphProperties(el["w:pPr"]);
114
+ const layer = {
115
+ ...borders ? { borders } : {},
116
+ ...cellMargins ? { cellMargins } : {},
117
+ ...shading ? { shading } : {},
118
+ ...Object.keys(runProperties).length > 0 ? { runProperties } : {},
119
+ ...Object.keys(paragraphProperties).length > 0 ? { paragraphProperties } : {}
120
+ };
121
+ return Object.keys(layer).length > 0 ? layer : void 0;
122
+ }
123
+ var FLAT_BORDER_STYLES = new Set([
124
+ "none",
125
+ "single",
126
+ "double",
127
+ "thick",
128
+ "dotted",
129
+ "dashed"
130
+ ]);
131
+ function parseFlatBorder(node) {
132
+ const el = asElement(node);
133
+ if (!el) return void 0;
134
+ const val = getAttr(el, "val");
135
+ if (!val || !FLAT_BORDER_STYLES.has(val)) return void 0;
136
+ const szRaw = getAttr(el, "sz");
137
+ const sz = szRaw !== void 0 ? Number(szRaw) : NaN;
138
+ const color = getAttr(el, "color");
139
+ return {
140
+ style: val,
141
+ ...Number.isFinite(sz) ? { width: eighthPtToPt(sz) } : {},
142
+ ...color && color !== "auto" && /^[0-9A-Fa-f]{6}$/.test(color) ? { colorHex: color.toUpperCase() } : {}
143
+ };
144
+ }
145
+ function parseFlatBorders(el) {
146
+ if (!el) return void 0;
147
+ const top = parseFlatBorder(el["w:top"]);
148
+ const right = parseFlatBorder(el["w:right"] ?? el["w:end"]);
149
+ const bottom = parseFlatBorder(el["w:bottom"]);
150
+ const left = parseFlatBorder(el["w:left"] ?? el["w:start"]);
151
+ const insideH = parseFlatBorder(el["w:insideH"]);
152
+ const insideV = parseFlatBorder(el["w:insideV"]);
153
+ const out = {
154
+ ...top ? { top } : {},
155
+ ...right ? { right } : {},
156
+ ...bottom ? { bottom } : {},
157
+ ...left ? { left } : {},
158
+ ...insideH ? { insideH } : {},
159
+ ...insideV ? { insideV } : {}
160
+ };
161
+ return Object.keys(out).length > 0 ? out : void 0;
162
+ }
163
+ function parseFlatCellMargins(el) {
164
+ if (!el) return void 0;
165
+ const read = (node) => {
166
+ const m = asElement(node);
167
+ if (!m) return void 0;
168
+ const w = getAttr(m, "w");
169
+ const n = w !== void 0 ? Number(w) : NaN;
170
+ return Number.isFinite(n) ? n : void 0;
171
+ };
172
+ const top = read(el["w:top"]);
173
+ const bottom = read(el["w:bottom"]);
174
+ const left = read(el["w:left"] ?? el["w:start"]);
175
+ const right = read(el["w:right"] ?? el["w:end"]);
176
+ const out = {
177
+ ...top !== void 0 ? { top: twipsToPt(top) } : {},
178
+ ...bottom !== void 0 ? { bottom: twipsToPt(bottom) } : {},
179
+ ...left !== void 0 ? { left: twipsToPt(left) } : {},
180
+ ...right !== void 0 ? { right: twipsToPt(right) } : {}
181
+ };
182
+ return Object.keys(out).length > 0 ? out : void 0;
183
+ }
184
+ function parseFlatShading(node) {
185
+ const el = asElement(node);
186
+ if (!el) return void 0;
187
+ const fill = getAttr(el, "fill");
188
+ if (fill && fill !== "auto" && /^[0-9A-Fa-f]{6}$/.test(fill)) return { colorHex: fill.toUpperCase() };
189
+ }
190
+ function intVal(node) {
191
+ const v = getVal(node);
192
+ if (v === void 0) return void 0;
193
+ const n = Number(v);
194
+ return Number.isFinite(n) ? n : void 0;
195
+ }
63
196
  //#endregion
64
197
  export { parseStyles };