@shadow-garden/bapbong-docx 0.1.0 → 0.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.
- package/dist/index.cjs +304 -77
- package/dist/index.js +304 -77
- package/dist/lib/docx.d.ts.map +1 -1
- package/dist/lib/export.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -385,11 +385,16 @@ function propsToMarks(p, ctx) {
|
|
|
385
385
|
if (p.italic) marks.push(ctx.schema.marks["em"].create());
|
|
386
386
|
if (p.underline) marks.push(ctx.schema.marks["underline"].create());
|
|
387
387
|
if (p.strike) marks.push(ctx.schema.marks["strike"].create());
|
|
388
|
-
if (p.color)
|
|
389
|
-
|
|
390
|
-
if (p.
|
|
391
|
-
|
|
392
|
-
if (p.
|
|
388
|
+
if (p.color)
|
|
389
|
+
marks.push(ctx.schema.marks["textColor"].create({ color: p.color }));
|
|
390
|
+
if (p.sizePt !== void 0)
|
|
391
|
+
marks.push(ctx.schema.marks["fontSize"].create({ size: p.sizePt }));
|
|
392
|
+
if (p.fontFamily)
|
|
393
|
+
marks.push(ctx.schema.marks["fontFamily"].create({ family: p.fontFamily }));
|
|
394
|
+
if (p.highlight)
|
|
395
|
+
marks.push(ctx.schema.marks["highlight"].create({ color: p.highlight }));
|
|
396
|
+
if (p.vertAlign)
|
|
397
|
+
marks.push(ctx.schema.marks["vertAlign"].create({ value: p.vertAlign }));
|
|
393
398
|
return marks;
|
|
394
399
|
}
|
|
395
400
|
var SYMBOL_MAP = {
|
|
@@ -409,7 +414,9 @@ function symbolChar(code) {
|
|
|
409
414
|
return Number.isNaN(n) ? "" : String.fromCodePoint(n >= 61440 ? n - 61440 + 32 : n);
|
|
410
415
|
}
|
|
411
416
|
function hasPageBreak(run) {
|
|
412
|
-
return run.children.some(
|
|
417
|
+
return run.children.some(
|
|
418
|
+
(n) => n.name === "w:br" && attrOf(n, "w:type") === "page"
|
|
419
|
+
);
|
|
413
420
|
}
|
|
414
421
|
function effectiveChildren(nodes) {
|
|
415
422
|
const out = [];
|
|
@@ -458,8 +465,12 @@ function runInlineNodes(run, marks, ctx) {
|
|
|
458
465
|
if (id && ctx.notes.bodies[kind].has(id)) {
|
|
459
466
|
flush();
|
|
460
467
|
const num = ctx.notes.ref(kind, id);
|
|
461
|
-
const refMarks = [
|
|
462
|
-
|
|
468
|
+
const refMarks = [
|
|
469
|
+
...marks,
|
|
470
|
+
ctx.schema.marks["vertAlign"].create({ value: "super" })
|
|
471
|
+
];
|
|
472
|
+
if (kind === "footnote")
|
|
473
|
+
refMarks.push(ctx.schema.marks["footnote"].create({ num }));
|
|
463
474
|
out.push(ctx.schema.text(String(num), refMarks));
|
|
464
475
|
}
|
|
465
476
|
} else if (node.name === "w:br" && attrOf(node, "w:type") !== "page") {
|
|
@@ -483,9 +494,11 @@ function parseAnchorFloat(drawing) {
|
|
|
483
494
|
const posH = child(anchor, "wp:positionH");
|
|
484
495
|
if (posH) {
|
|
485
496
|
const align = child(posH, "wp:align")?.text.trim();
|
|
486
|
-
if (align === "left" || align === "right" || align === "center")
|
|
497
|
+
if (align === "left" || align === "right" || align === "center")
|
|
498
|
+
float["hAlign"] = align;
|
|
487
499
|
const off = emuToPxZero(child(posH, "wp:posOffset")?.text);
|
|
488
|
-
if (off !== void 0 && float["hAlign"] === void 0)
|
|
500
|
+
if (off !== void 0 && float["hAlign"] === void 0)
|
|
501
|
+
float["hOffset"] = off;
|
|
489
502
|
const rel = attrOf(posH, "relativeFrom");
|
|
490
503
|
float["hRel"] = rel === "page" ? "page" : "margin";
|
|
491
504
|
}
|
|
@@ -662,7 +675,9 @@ function parseShape(run, ctx) {
|
|
|
662
675
|
function parseTextbox(wsp, ctx) {
|
|
663
676
|
const content = child(child(wsp, "wps:txbx"), "w:txbxContent");
|
|
664
677
|
if (!content) return null;
|
|
665
|
-
const paragraphs = children(content, "w:p").map(
|
|
678
|
+
const paragraphs = children(content, "w:p").map(
|
|
679
|
+
(p) => parseParagraph(p, ctx).toJSON()
|
|
680
|
+
);
|
|
666
681
|
if (paragraphs.length === 0) return null;
|
|
667
682
|
const bodyPr = child(wsp, "wps:bodyPr");
|
|
668
683
|
const ins = (name) => emuToPxZero(attrOf(bodyPr, name));
|
|
@@ -757,7 +772,10 @@ function flattenOmml(node) {
|
|
|
757
772
|
function parseParagraph(p, ctx) {
|
|
758
773
|
const pPr = child(p, "w:pPr");
|
|
759
774
|
const pStyleId = attrOf(child(pPr, "w:pStyle"), "w:val");
|
|
760
|
-
const paraBase = mergeRunProps(
|
|
775
|
+
const paraBase = mergeRunProps(
|
|
776
|
+
ctx.styles.docDefaults,
|
|
777
|
+
ctx.styles.resolveStyle(pStyleId)
|
|
778
|
+
);
|
|
761
779
|
const pPrChain = [
|
|
762
780
|
ctx.styles.docDefaultsPPr,
|
|
763
781
|
...ctx.styles.resolveStylePPr(pStyleId),
|
|
@@ -790,9 +808,12 @@ function parseParagraph(p, ctx) {
|
|
|
790
808
|
} else if (fldType === "end") {
|
|
791
809
|
const kind = fieldKind(field.instr);
|
|
792
810
|
if (kind) {
|
|
793
|
-
inline.push(
|
|
811
|
+
inline.push(
|
|
812
|
+
pageFieldNode(kind, field.resultRuns[0], paraBase, ctx)
|
|
813
|
+
);
|
|
794
814
|
} else {
|
|
795
|
-
for (const r of field.resultRuns)
|
|
815
|
+
for (const r of field.resultRuns)
|
|
816
|
+
inline.push(...runToInline(r, paraBase, ctx, null));
|
|
796
817
|
}
|
|
797
818
|
field = null;
|
|
798
819
|
} else if (field.phase === "instr") {
|
|
@@ -809,7 +830,8 @@ function parseParagraph(p, ctx) {
|
|
|
809
830
|
if (kind) {
|
|
810
831
|
inline.push(pageFieldNode(kind, resultRuns[0], paraBase, ctx));
|
|
811
832
|
} else {
|
|
812
|
-
for (const r of resultRuns)
|
|
833
|
+
for (const r of resultRuns)
|
|
834
|
+
inline.push(...runToInline(r, paraBase, ctx, null));
|
|
813
835
|
}
|
|
814
836
|
} else if (node.name === "w:hyperlink") {
|
|
815
837
|
const rel = attrOf(node, "r:id") ? ctx.rels.get(attrOf(node, "r:id")) : void 0;
|
|
@@ -822,7 +844,9 @@ function parseParagraph(p, ctx) {
|
|
|
822
844
|
const text = flattenOmml(node);
|
|
823
845
|
if (text.length > 0) {
|
|
824
846
|
const first = findDescendant(node, "m:r");
|
|
825
|
-
inline.push(
|
|
847
|
+
inline.push(
|
|
848
|
+
ctx.schema.text(text, runMarks(first, paraBase, ctx, null))
|
|
849
|
+
);
|
|
826
850
|
}
|
|
827
851
|
} else if (node.name === "w:commentRangeStart") {
|
|
828
852
|
const id = Number(attrOf(node, "w:id"));
|
|
@@ -839,6 +863,9 @@ function parseParagraph(p, ctx) {
|
|
|
839
863
|
if (list) attrs.list = list;
|
|
840
864
|
if (align) attrs.align = align;
|
|
841
865
|
if (heading) attrs.heading = heading;
|
|
866
|
+
else if (pStyleId && /^(title|subtitle)$/i.test(pStyleId)) {
|
|
867
|
+
attrs.styleId = pStyleId.toLowerCase() === "title" ? "Title" : "Subtitle";
|
|
868
|
+
}
|
|
842
869
|
if (indent) attrs.indent = indent;
|
|
843
870
|
if (spacing) attrs.spacing = spacing;
|
|
844
871
|
if (tabs) attrs.tabs = tabs;
|
|
@@ -951,7 +978,9 @@ function parseList(pPr) {
|
|
|
951
978
|
return { numId, level: Number.isNaN(ilvl) ? 0 : ilvl };
|
|
952
979
|
}
|
|
953
980
|
function emptyCell(ctx) {
|
|
954
|
-
return ctx.schema.nodes["table_cell"].create(null, [
|
|
981
|
+
return ctx.schema.nodes["table_cell"].create(null, [
|
|
982
|
+
ctx.schema.nodes["paragraph"].create()
|
|
983
|
+
]);
|
|
955
984
|
}
|
|
956
985
|
function parseCellMargins(tbl) {
|
|
957
986
|
const mar = child(child(tbl, "w:tblPr"), "w:tblCellMar");
|
|
@@ -1004,7 +1033,14 @@ function parseBordersEl(bordersEl, sides) {
|
|
|
1004
1033
|
}
|
|
1005
1034
|
return Object.keys(out).length > 0 ? out : null;
|
|
1006
1035
|
}
|
|
1007
|
-
var TABLE_SIDES = [
|
|
1036
|
+
var TABLE_SIDES = [
|
|
1037
|
+
"top",
|
|
1038
|
+
"bottom",
|
|
1039
|
+
"left",
|
|
1040
|
+
"right",
|
|
1041
|
+
"insideH",
|
|
1042
|
+
"insideV"
|
|
1043
|
+
];
|
|
1008
1044
|
var CELL_SIDES = ["top", "bottom", "left", "right"];
|
|
1009
1045
|
function parseTableBorders(tbl, ctx) {
|
|
1010
1046
|
const tblPr = child(tbl, "w:tblPr");
|
|
@@ -1031,8 +1067,18 @@ function parseTable(tbl, ctx) {
|
|
|
1031
1067
|
const vAlign = vAlignVal === "center" || vAlignVal === "bottom" ? vAlignVal : null;
|
|
1032
1068
|
const borders2 = parseBordersEl(child(tcPr, "w:tcBorders"), CELL_SIDES);
|
|
1033
1069
|
const content = parseBlocks(tc, ctx);
|
|
1034
|
-
if (content.length === 0)
|
|
1035
|
-
|
|
1070
|
+
if (content.length === 0)
|
|
1071
|
+
content.push(ctx.schema.nodes["paragraph"].create());
|
|
1072
|
+
cells.push({
|
|
1073
|
+
startCol: col,
|
|
1074
|
+
colspan,
|
|
1075
|
+
vMerge,
|
|
1076
|
+
colwidth: widths.length ? widths : null,
|
|
1077
|
+
background,
|
|
1078
|
+
vAlign,
|
|
1079
|
+
borders: borders2,
|
|
1080
|
+
content
|
|
1081
|
+
});
|
|
1036
1082
|
col += colspan;
|
|
1037
1083
|
}
|
|
1038
1084
|
return cells;
|
|
@@ -1043,12 +1089,17 @@ function parseTable(tbl, ctx) {
|
|
|
1043
1089
|
const header = hdr ? attrOf(hdr, "w:val") !== "false" && attrOf(hdr, "w:val") !== "0" : false;
|
|
1044
1090
|
const trH = child(trPr, "w:trHeight");
|
|
1045
1091
|
const hv = attrOf(trH, "w:val");
|
|
1046
|
-
const height = hv !== void 0 ? {
|
|
1092
|
+
const height = hv !== void 0 ? {
|
|
1093
|
+
value: twipsToPx(Number(hv)),
|
|
1094
|
+
exact: attrOf(trH, "w:hRule") === "exact"
|
|
1095
|
+
} : null;
|
|
1047
1096
|
const cs = child(trPr, "w:cantSplit");
|
|
1048
1097
|
const cantSplit = cs ? attrOf(cs, "w:val") !== "false" && attrOf(cs, "w:val") !== "0" : false;
|
|
1049
1098
|
return { header, height, cantSplit };
|
|
1050
1099
|
});
|
|
1051
|
-
const colIndex = logicalRows.map(
|
|
1100
|
+
const colIndex = logicalRows.map(
|
|
1101
|
+
(cells) => new Map(cells.map((c) => [c.startCol, c]))
|
|
1102
|
+
);
|
|
1052
1103
|
const rows = logicalRows.map((cells, r) => {
|
|
1053
1104
|
const emitted = [];
|
|
1054
1105
|
for (const cell of cells) {
|
|
@@ -1089,7 +1140,8 @@ function parseTable(tbl, ctx) {
|
|
|
1089
1140
|
const attrs = {};
|
|
1090
1141
|
if (cellPadding) attrs["cellPadding"] = cellPadding;
|
|
1091
1142
|
if (borders) attrs["borders"] = borders;
|
|
1092
|
-
if (jc === "center" || jc === "right" || jc === "end")
|
|
1143
|
+
if (jc === "center" || jc === "right" || jc === "end")
|
|
1144
|
+
attrs["align"] = jc === "end" ? "right" : jc;
|
|
1093
1145
|
return ctx.schema.nodes["table"].create(
|
|
1094
1146
|
Object.keys(attrs).length > 0 ? attrs : null,
|
|
1095
1147
|
rows.length > 0 ? rows : [ctx.schema.nodes["table_row"].create(null, [emptyCell(ctx)])]
|
|
@@ -1155,18 +1207,27 @@ async function readPartRels(zip, partPath) {
|
|
|
1155
1207
|
return xml ? parseXml(xml) : void 0;
|
|
1156
1208
|
}
|
|
1157
1209
|
async function buildNotesRegistry(zip) {
|
|
1158
|
-
const bodies = {
|
|
1210
|
+
const bodies = {
|
|
1211
|
+
footnote: /* @__PURE__ */ new Map(),
|
|
1212
|
+
endnote: /* @__PURE__ */ new Map()
|
|
1213
|
+
};
|
|
1159
1214
|
const load = async (path, root, tag, into) => {
|
|
1160
1215
|
const xml = await readPart(zip, path);
|
|
1161
1216
|
if (!xml) return;
|
|
1162
1217
|
for (const note of children(child(parseXml(xml), root), tag)) {
|
|
1163
1218
|
const id = attrOf(note, "w:id");
|
|
1164
1219
|
const type = attrOf(note, "w:type");
|
|
1165
|
-
if (id === void 0 || Number(id) < 1 || type && type !== "normal")
|
|
1220
|
+
if (id === void 0 || Number(id) < 1 || type && type !== "normal")
|
|
1221
|
+
continue;
|
|
1166
1222
|
into.set(id, note);
|
|
1167
1223
|
}
|
|
1168
1224
|
};
|
|
1169
|
-
await load(
|
|
1225
|
+
await load(
|
|
1226
|
+
"word/footnotes.xml",
|
|
1227
|
+
"w:footnotes",
|
|
1228
|
+
"w:footnote",
|
|
1229
|
+
bodies.footnote
|
|
1230
|
+
);
|
|
1170
1231
|
await load("word/endnotes.xml", "w:endnotes", "w:endnote", bodies.endnote);
|
|
1171
1232
|
const reg = {
|
|
1172
1233
|
bodies,
|
|
@@ -1201,7 +1262,10 @@ async function buildCommentsRegistry(zip) {
|
|
|
1201
1262
|
const ext = /* @__PURE__ */ new Map();
|
|
1202
1263
|
const extXml = await readPart(zip, "word/commentsExtended.xml");
|
|
1203
1264
|
if (extXml) {
|
|
1204
|
-
for (const ex of children(
|
|
1265
|
+
for (const ex of children(
|
|
1266
|
+
child(parseXml(extXml), "w15:commentsEx"),
|
|
1267
|
+
"w15:commentEx"
|
|
1268
|
+
)) {
|
|
1205
1269
|
const paraId2 = attrOf(ex, "w15:paraId");
|
|
1206
1270
|
if (!paraId2) continue;
|
|
1207
1271
|
const done = attrOf(ex, "w15:done");
|
|
@@ -1221,14 +1285,24 @@ function buildCommentsList(ctx) {
|
|
|
1221
1285
|
const out = [];
|
|
1222
1286
|
for (const id of ctx.comments.used) {
|
|
1223
1287
|
const def = ctx.comments.defs.get(id);
|
|
1224
|
-
if (def)
|
|
1288
|
+
if (def)
|
|
1289
|
+
out.push({
|
|
1290
|
+
id,
|
|
1291
|
+
author: def.author,
|
|
1292
|
+
date: def.date,
|
|
1293
|
+
text: collectText(def.body).trim()
|
|
1294
|
+
});
|
|
1225
1295
|
}
|
|
1226
1296
|
return out;
|
|
1227
1297
|
}
|
|
1228
1298
|
function commentBodyJSON(comment) {
|
|
1229
1299
|
const paras = children(comment, "w:p").map((p) => {
|
|
1230
1300
|
const text = collectText(p);
|
|
1231
|
-
return import_bapbong_model.commentSchema.node(
|
|
1301
|
+
return import_bapbong_model.commentSchema.node(
|
|
1302
|
+
"paragraph",
|
|
1303
|
+
null,
|
|
1304
|
+
text ? [import_bapbong_model.commentSchema.text(text)] : []
|
|
1305
|
+
);
|
|
1232
1306
|
});
|
|
1233
1307
|
return import_bapbong_model.commentSchema.node("doc", null, paras.length ? paras : [import_bapbong_model.commentSchema.node("paragraph")]).toJSON();
|
|
1234
1308
|
}
|
|
@@ -1248,12 +1322,18 @@ function buildCommentNodes(ctx) {
|
|
|
1248
1322
|
if (usedSet.has(cur)) return true;
|
|
1249
1323
|
return false;
|
|
1250
1324
|
};
|
|
1251
|
-
const ids = [
|
|
1325
|
+
const ids = [
|
|
1326
|
+
...used.filter((id) => defs.has(id)),
|
|
1327
|
+
...[...defs.keys()].filter((id) => !usedSet.has(id))
|
|
1328
|
+
];
|
|
1252
1329
|
const out = [];
|
|
1253
1330
|
for (const id of ids) {
|
|
1254
1331
|
const def = defs.get(id);
|
|
1255
1332
|
if (!def || !referenced(id)) continue;
|
|
1256
|
-
const user = {
|
|
1333
|
+
const user = {
|
|
1334
|
+
id: def.author || "unknown",
|
|
1335
|
+
name: def.author || "Unknown"
|
|
1336
|
+
};
|
|
1257
1337
|
out.push({
|
|
1258
1338
|
id,
|
|
1259
1339
|
parentId: parentOf.get(id) ?? null,
|
|
@@ -1267,7 +1347,9 @@ function buildCommentNodes(ctx) {
|
|
|
1267
1347
|
}
|
|
1268
1348
|
function noteBlocks(note, num, ctx) {
|
|
1269
1349
|
const blocks = parseBlocks(note, ctx);
|
|
1270
|
-
const marker = ctx.schema.text(`${num}. `, [
|
|
1350
|
+
const marker = ctx.schema.text(`${num}. `, [
|
|
1351
|
+
ctx.schema.marks["vertAlign"].create({ value: "super" })
|
|
1352
|
+
]);
|
|
1271
1353
|
const first = blocks[0];
|
|
1272
1354
|
if (first && first.type.name === "paragraph") {
|
|
1273
1355
|
const kids = [marker];
|
|
@@ -1317,7 +1399,10 @@ async function extractMedia(zip) {
|
|
|
1317
1399
|
if (!path.startsWith("word/media/")) continue;
|
|
1318
1400
|
const entry = zip.file(path);
|
|
1319
1401
|
if (!entry || entry.dir) continue;
|
|
1320
|
-
media.set(
|
|
1402
|
+
media.set(
|
|
1403
|
+
path,
|
|
1404
|
+
`data:${mimeOf(path)};base64,${await entry.async("base64")}`
|
|
1405
|
+
);
|
|
1321
1406
|
}
|
|
1322
1407
|
return media;
|
|
1323
1408
|
}
|
|
@@ -1327,11 +1412,16 @@ async function importDocx(input, opts) {
|
|
|
1327
1412
|
if (rawDocumentXml === void 0) {
|
|
1328
1413
|
throw new Error("bapbong-docx: word/document.xml not found in archive");
|
|
1329
1414
|
}
|
|
1330
|
-
const
|
|
1415
|
+
const stylesXml2 = await readPart(zip, "word/styles.xml");
|
|
1331
1416
|
const numberingXml = await readPart(zip, "word/numbering.xml");
|
|
1332
1417
|
const themeXml = await readPart(zip, "word/theme/theme1.xml");
|
|
1333
|
-
const resolveTheme = buildThemeResolver(
|
|
1334
|
-
|
|
1418
|
+
const resolveTheme = buildThemeResolver(
|
|
1419
|
+
themeXml ? parseXml(themeXml) : void 0
|
|
1420
|
+
);
|
|
1421
|
+
const styles = buildStyleRegistry(
|
|
1422
|
+
stylesXml2 ? parseXml(stylesXml2) : void 0,
|
|
1423
|
+
resolveTheme
|
|
1424
|
+
);
|
|
1335
1425
|
const numberingRoot = numberingXml ? parseXml(numberingXml) : void 0;
|
|
1336
1426
|
const media = await extractMedia(zip);
|
|
1337
1427
|
const notes = await buildNotesRegistry(zip);
|
|
@@ -1380,7 +1470,11 @@ async function importDocx(input, opts) {
|
|
|
1380
1470
|
if (!xml) continue;
|
|
1381
1471
|
const partCtx = makeCtx(buildRels(await readPartRels(zip, partPath)));
|
|
1382
1472
|
const el = child(parseXml(xml), root);
|
|
1383
|
-
store[type] = storyDoc(
|
|
1473
|
+
store[type] = storyDoc(
|
|
1474
|
+
partCtx,
|
|
1475
|
+
el ? parseBlocks(el, partCtx) : [],
|
|
1476
|
+
ctx.numbering.defs
|
|
1477
|
+
);
|
|
1384
1478
|
}
|
|
1385
1479
|
};
|
|
1386
1480
|
await collect("w:headerReference", headers, "w:hdr");
|
|
@@ -1457,7 +1551,10 @@ var pxToEmu = (px) => Math.round(px * 9525);
|
|
|
1457
1551
|
var commentIdsOf = (node) => node.marks.find((m) => m.type.name === "comment")?.attrs["ids"] ?? [];
|
|
1458
1552
|
var isInlineLeaf = (node) => node.isText || node.type.name === "image" || node.type.name === "hard_break";
|
|
1459
1553
|
function esc(s) {
|
|
1460
|
-
return s.replace(
|
|
1554
|
+
return s.replace(
|
|
1555
|
+
/[&<>"]/g,
|
|
1556
|
+
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]
|
|
1557
|
+
);
|
|
1461
1558
|
}
|
|
1462
1559
|
var MIME_EXT = {
|
|
1463
1560
|
"image/png": "png",
|
|
@@ -1480,9 +1577,15 @@ function runProps(marks) {
|
|
|
1480
1577
|
const size = byName.get("fontSize")?.attrs["size"];
|
|
1481
1578
|
if (size != null) out.push(`<w:sz w:val="${Math.round(size * 2)}"/>`);
|
|
1482
1579
|
const hl = byName.get("highlight")?.attrs["color"];
|
|
1483
|
-
if (hl)
|
|
1580
|
+
if (hl)
|
|
1581
|
+
out.push(
|
|
1582
|
+
`<w:shd w:val="clear" w:color="auto" w:fill="${hl.replace(/^#/, "")}"/>`
|
|
1583
|
+
);
|
|
1484
1584
|
const va = byName.get("vertAlign")?.attrs["value"];
|
|
1485
|
-
if (va)
|
|
1585
|
+
if (va)
|
|
1586
|
+
out.push(
|
|
1587
|
+
`<w:vertAlign w:val="${va === "sub" ? "subscript" : "superscript"}"/>`
|
|
1588
|
+
);
|
|
1486
1589
|
return out.length ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
1487
1590
|
}
|
|
1488
1591
|
function anchorXml(float, cx, cy, n, graphic) {
|
|
@@ -1524,7 +1627,9 @@ function imageXml(node, ctx) {
|
|
|
1524
1627
|
const n = ctx.nextId++;
|
|
1525
1628
|
const rid = `rId${n}`;
|
|
1526
1629
|
ctx.media.push({ path: `word/media/image${n}.${ext}`, base64: m[2] });
|
|
1527
|
-
ctx.rels.push(
|
|
1630
|
+
ctx.rels.push(
|
|
1631
|
+
`<Relationship Id="${rid}" Type="${R_NS}/image" Target="media/image${n}.${ext}"/>`
|
|
1632
|
+
);
|
|
1528
1633
|
const cx = pxToEmu(node.attrs["width"] ?? 96);
|
|
1529
1634
|
const cy = pxToEmu(node.attrs["height"] ?? 96);
|
|
1530
1635
|
return `<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${n}" name="Picture ${n}"/><a:graphic><a:graphicData uri="${PIC_NS}"><pic:pic><pic:nvPicPr><pic:cNvPr id="${n}" name="image${n}.${ext}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${rid}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm${rotAttr(node)}><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;
|
|
@@ -1534,7 +1639,8 @@ function inlineXml(node, ctx) {
|
|
|
1534
1639
|
if (node.type.name === "image") return imageXml(node, ctx);
|
|
1535
1640
|
if (node.isText) {
|
|
1536
1641
|
const fn = node.marks.find((m) => m.type.name === "footnote");
|
|
1537
|
-
if (fn)
|
|
1642
|
+
if (fn)
|
|
1643
|
+
return `<w:r>${runProps(node.marks)}<w:footnoteReference w:id="${fn.attrs["num"]}"/></w:r>`;
|
|
1538
1644
|
return `<w:r>${runProps(node.marks)}<w:t xml:space="preserve">${esc(node.text ?? "")}</w:t></w:r>`;
|
|
1539
1645
|
}
|
|
1540
1646
|
return "";
|
|
@@ -1544,9 +1650,12 @@ function inlineUnit(node, ctx) {
|
|
|
1544
1650
|
const inner = inlineXml(node, ctx);
|
|
1545
1651
|
const href = linkHref(node);
|
|
1546
1652
|
if (!href || !inner) return inner;
|
|
1547
|
-
if (href.startsWith("#"))
|
|
1653
|
+
if (href.startsWith("#"))
|
|
1654
|
+
return `<w:hyperlink w:anchor="${esc(href.slice(1))}">${inner}</w:hyperlink>`;
|
|
1548
1655
|
const n = ctx.nextId++;
|
|
1549
|
-
ctx.rels.push(
|
|
1656
|
+
ctx.rels.push(
|
|
1657
|
+
`<Relationship Id="rId${n}" Type="${R_NS}/hyperlink" Target="${esc(href)}" TargetMode="External"/>`
|
|
1658
|
+
);
|
|
1550
1659
|
return `<w:hyperlink r:id="rId${n}">${inner}</w:hyperlink>`;
|
|
1551
1660
|
}
|
|
1552
1661
|
function inlineContent(node, ctx) {
|
|
@@ -1580,10 +1689,16 @@ function paraProps(node) {
|
|
|
1580
1689
|
const a = node.attrs;
|
|
1581
1690
|
const out = [];
|
|
1582
1691
|
const heading = a["heading"];
|
|
1692
|
+
const styleId = a["styleId"];
|
|
1583
1693
|
if (heading) out.push(`<w:pStyle w:val="Heading${heading}"/>`);
|
|
1694
|
+
else if (styleId === "Title" || styleId === "Subtitle")
|
|
1695
|
+
out.push(`<w:pStyle w:val="${styleId}"/>`);
|
|
1584
1696
|
if (a["pageBreakBefore"]) out.push("<w:pageBreakBefore/>");
|
|
1585
1697
|
const list = a["list"];
|
|
1586
|
-
if (list)
|
|
1698
|
+
if (list)
|
|
1699
|
+
out.push(
|
|
1700
|
+
`<w:numPr><w:ilvl w:val="${list.level}"/><w:numId w:val="${esc(list.numId)}"/></w:numPr>`
|
|
1701
|
+
);
|
|
1587
1702
|
const sp = a["spacing"];
|
|
1588
1703
|
if (sp) {
|
|
1589
1704
|
const at = [];
|
|
@@ -1591,7 +1706,9 @@ function paraProps(node) {
|
|
|
1591
1706
|
if (sp.after != null) at.push(`w:after="${pxToTwips(sp.after)}"`);
|
|
1592
1707
|
if (sp.line != null) {
|
|
1593
1708
|
const auto = sp.lineRule === "auto" || sp.lineRule == null;
|
|
1594
|
-
at.push(
|
|
1709
|
+
at.push(
|
|
1710
|
+
`w:line="${auto ? Math.round(sp.line * 240) : pxToTwips(sp.line)}"`
|
|
1711
|
+
);
|
|
1595
1712
|
at.push(`w:lineRule="${sp.lineRule ?? "auto"}"`);
|
|
1596
1713
|
}
|
|
1597
1714
|
if (at.length) out.push(`<w:spacing ${at.join(" ")}/>`);
|
|
@@ -1602,11 +1719,13 @@ function paraProps(node) {
|
|
|
1602
1719
|
if (ind.left != null) at.push(`w:left="${pxToTwips(ind.left)}"`);
|
|
1603
1720
|
if (ind.right != null) at.push(`w:right="${pxToTwips(ind.right)}"`);
|
|
1604
1721
|
if (ind.hanging != null) at.push(`w:hanging="${pxToTwips(ind.hanging)}"`);
|
|
1605
|
-
else if (ind.firstLine != null)
|
|
1722
|
+
else if (ind.firstLine != null)
|
|
1723
|
+
at.push(`w:firstLine="${pxToTwips(ind.firstLine)}"`);
|
|
1606
1724
|
if (at.length) out.push(`<w:ind ${at.join(" ")}/>`);
|
|
1607
1725
|
}
|
|
1608
1726
|
const align = a["align"];
|
|
1609
|
-
if (align)
|
|
1727
|
+
if (align)
|
|
1728
|
+
out.push(`<w:jc w:val="${align === "justify" ? "both" : align}"/>`);
|
|
1610
1729
|
return out.join("");
|
|
1611
1730
|
}
|
|
1612
1731
|
function paragraphXml(node, ctx, sectPr = "") {
|
|
@@ -1614,7 +1733,14 @@ function paragraphXml(node, ctx, sectPr = "") {
|
|
|
1614
1733
|
const pPr = props ? `<w:pPr>${props}</w:pPr>` : "";
|
|
1615
1734
|
return `<w:p>${pPr}${inlineContent(node, ctx)}</w:p>`;
|
|
1616
1735
|
}
|
|
1617
|
-
var TABLE_SIDES2 = [
|
|
1736
|
+
var TABLE_SIDES2 = [
|
|
1737
|
+
"top",
|
|
1738
|
+
"bottom",
|
|
1739
|
+
"left",
|
|
1740
|
+
"right",
|
|
1741
|
+
"insideH",
|
|
1742
|
+
"insideV"
|
|
1743
|
+
];
|
|
1618
1744
|
var CELL_SIDES2 = ["top", "bottom", "left", "right"];
|
|
1619
1745
|
var BORDER_STYLE_OUT = {
|
|
1620
1746
|
solid: "single",
|
|
@@ -1636,12 +1762,19 @@ function cellXml(cell, ctx) {
|
|
|
1636
1762
|
const a = cell.attrs;
|
|
1637
1763
|
const pr = [];
|
|
1638
1764
|
const colwidth = a["colwidth"];
|
|
1639
|
-
if (colwidth?.length)
|
|
1640
|
-
|
|
1765
|
+
if (colwidth?.length)
|
|
1766
|
+
pr.push(
|
|
1767
|
+
`<w:tcW w:w="${pxToTwips(colwidth.reduce((x, y) => x + y, 0))}" w:type="dxa"/>`
|
|
1768
|
+
);
|
|
1769
|
+
if (a["colspan"] > 1)
|
|
1770
|
+
pr.push(`<w:gridSpan w:val="${a["colspan"]}"/>`);
|
|
1641
1771
|
const borders = a["borders"];
|
|
1642
1772
|
if (borders) pr.push(bordersXml("w:tcBorders", borders, CELL_SIDES2));
|
|
1643
1773
|
const bg = a["background"];
|
|
1644
|
-
if (bg)
|
|
1774
|
+
if (bg)
|
|
1775
|
+
pr.push(
|
|
1776
|
+
`<w:shd w:val="clear" w:color="auto" w:fill="${bg.replace(/^#/, "")}"/>`
|
|
1777
|
+
);
|
|
1645
1778
|
const vAlign = a["vAlign"];
|
|
1646
1779
|
if (vAlign) pr.push(`<w:vAlign w:val="${vAlign}"/>`);
|
|
1647
1780
|
let content = "";
|
|
@@ -1654,7 +1787,10 @@ function rowXml(row, ctx) {
|
|
|
1654
1787
|
if (row.attrs["header"]) pr.push("<w:tblHeader/>");
|
|
1655
1788
|
if (row.attrs["cantSplit"]) pr.push("<w:cantSplit/>");
|
|
1656
1789
|
const h = row.attrs["height"];
|
|
1657
|
-
if (h)
|
|
1790
|
+
if (h)
|
|
1791
|
+
pr.push(
|
|
1792
|
+
`<w:trHeight w:val="${pxToTwips(h.value)}" w:hRule="${h.exact ? "exact" : "atLeast"}"/>`
|
|
1793
|
+
);
|
|
1658
1794
|
const trPr = pr.length ? `<w:trPr>${pr.join("")}</w:trPr>` : "";
|
|
1659
1795
|
let cells = "";
|
|
1660
1796
|
row.forEach((c) => cells += cellXml(c, ctx));
|
|
@@ -1673,7 +1809,9 @@ function tableXml(node, ctx) {
|
|
|
1673
1809
|
}
|
|
1674
1810
|
const firstRow = node.firstChild;
|
|
1675
1811
|
const grid = [];
|
|
1676
|
-
firstRow?.forEach(
|
|
1812
|
+
firstRow?.forEach(
|
|
1813
|
+
(c) => c.attrs["colwidth"]?.forEach((w) => grid.push(w))
|
|
1814
|
+
);
|
|
1677
1815
|
const gridXml = grid.length ? `<w:tblGrid>${grid.map((w) => `<w:gridCol w:w="${pxToTwips(w)}"/>`).join("")}</w:tblGrid>` : "";
|
|
1678
1816
|
let rows = "";
|
|
1679
1817
|
node.forEach((r) => rows += rowXml(r, ctx));
|
|
@@ -1708,10 +1846,14 @@ function commentBodyXml(body, firstParaId) {
|
|
|
1708
1846
|
doc.forEach((p, _o, i) => {
|
|
1709
1847
|
let runs = "";
|
|
1710
1848
|
p.forEach((inline) => {
|
|
1711
|
-
if (inline.isText)
|
|
1712
|
-
|
|
1849
|
+
if (inline.isText)
|
|
1850
|
+
runs += `<w:r><w:t xml:space="preserve">${esc(inline.text ?? "")}</w:t></w:r>`;
|
|
1851
|
+
else if (inline.type.name === "mention")
|
|
1852
|
+
runs += `<w:r><w:t xml:space="preserve">@${esc(String(inline.attrs["label"] ?? ""))}</w:t></w:r>`;
|
|
1713
1853
|
});
|
|
1714
|
-
ps.push(
|
|
1854
|
+
ps.push(
|
|
1855
|
+
`<w:p${i === 0 ? ` w14:paraId="${firstParaId}"` : ""}>${runs}</w:p>`
|
|
1856
|
+
);
|
|
1715
1857
|
});
|
|
1716
1858
|
return ps.join("") || `<w:p w14:paraId="${firstParaId}"/>`;
|
|
1717
1859
|
}
|
|
@@ -1733,16 +1875,65 @@ function commentsExtendedXml(comments) {
|
|
|
1733
1875
|
}
|
|
1734
1876
|
var ROOT_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1735
1877
|
<Relationships xmlns="${PR_NS}"><Relationship Id="rId1" Type="${R_NS}/officeDocument" Target="word/document.xml"/></Relationships>`;
|
|
1878
|
+
var STYLE_DEFS = (() => {
|
|
1879
|
+
const heading = (level, halfPt) => `<w:style w:type="paragraph" w:styleId="Heading${level}"><w:name w:val="heading ${level}"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="120"/><w:outlineLvl w:val="${level - 1}"/></w:pPr><w:rPr><w:b/><w:sz w:val="${halfPt}"/><w:szCs w:val="${halfPt}"/></w:rPr></w:style>`;
|
|
1880
|
+
return {
|
|
1881
|
+
Heading1: heading(1, 48),
|
|
1882
|
+
Heading2: heading(2, 36),
|
|
1883
|
+
Heading3: heading(3, 28),
|
|
1884
|
+
Heading4: heading(4, 24),
|
|
1885
|
+
Heading5: heading(5, 22),
|
|
1886
|
+
Heading6: heading(6, 22),
|
|
1887
|
+
Title: `<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:sz w:val="56"/><w:szCs w:val="56"/></w:rPr></w:style>`,
|
|
1888
|
+
Subtitle: `<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:rPr><w:i/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr></w:style>`
|
|
1889
|
+
};
|
|
1890
|
+
})();
|
|
1891
|
+
function usedStyleIds(doc) {
|
|
1892
|
+
const used = /* @__PURE__ */ new Set();
|
|
1893
|
+
doc.descendants((n) => {
|
|
1894
|
+
if (n.type.name !== "paragraph") return;
|
|
1895
|
+
const heading = n.attrs["heading"];
|
|
1896
|
+
const styleId = n.attrs["styleId"];
|
|
1897
|
+
if (heading) used.add(`Heading${heading}`);
|
|
1898
|
+
else if (styleId && STYLE_DEFS[styleId]) used.add(styleId);
|
|
1899
|
+
});
|
|
1900
|
+
return used;
|
|
1901
|
+
}
|
|
1902
|
+
function stylesXml(used) {
|
|
1903
|
+
const defs = [...used].map((id) => STYLE_DEFS[id]).join("");
|
|
1904
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1905
|
+
<w:styles xmlns:w="${W_NS}"><w:docDefaults><w:rPrDefault><w:rPr><w:sz w:val="22"/><w:szCs w:val="22"/></w:rPr></w:rPrDefault><w:pPrDefault/></w:docDefaults><w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>` + defs + `</w:styles>`;
|
|
1906
|
+
}
|
|
1907
|
+
function mergeStyles(xml, used) {
|
|
1908
|
+
const missing = [...used].filter((id) => !xml.includes(`w:styleId="${id}"`));
|
|
1909
|
+
if (!missing.length) return xml;
|
|
1910
|
+
return xml.replace(
|
|
1911
|
+
"</w:styles>",
|
|
1912
|
+
`${missing.map((id) => STYLE_DEFS[id]).join("")}</w:styles>`
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1736
1915
|
function contentTypes(exts, hasComments) {
|
|
1737
1916
|
const parts = [
|
|
1738
1917
|
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>',
|
|
1739
1918
|
'<Default Extension="xml" ContentType="application/xml"/>'
|
|
1740
1919
|
];
|
|
1741
|
-
for (const ext of exts)
|
|
1742
|
-
|
|
1920
|
+
for (const ext of exts)
|
|
1921
|
+
parts.push(
|
|
1922
|
+
`<Default Extension="${ext}" ContentType="image/${ext === "jpg" ? "jpeg" : ext}"/>`
|
|
1923
|
+
);
|
|
1924
|
+
parts.push(
|
|
1925
|
+
'<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>'
|
|
1926
|
+
);
|
|
1927
|
+
parts.push(
|
|
1928
|
+
'<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>'
|
|
1929
|
+
);
|
|
1743
1930
|
if (hasComments) {
|
|
1744
|
-
parts.push(
|
|
1745
|
-
|
|
1931
|
+
parts.push(
|
|
1932
|
+
'<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>'
|
|
1933
|
+
);
|
|
1934
|
+
parts.push(
|
|
1935
|
+
'<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"/>'
|
|
1936
|
+
);
|
|
1746
1937
|
}
|
|
1747
1938
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1748
1939
|
<Types xmlns="${CT_NS}">${parts.join("")}</Types>`;
|
|
@@ -1750,17 +1941,30 @@ function contentTypes(exts, hasComments) {
|
|
|
1750
1941
|
function mergeContentTypes(xml, exts, hasComments) {
|
|
1751
1942
|
let out = xml;
|
|
1752
1943
|
const add = (frag, key) => {
|
|
1753
|
-
if (!out.includes(`"${key}"`))
|
|
1944
|
+
if (!out.includes(`"${key}"`))
|
|
1945
|
+
out = out.replace("</Types>", `${frag}</Types>`);
|
|
1754
1946
|
};
|
|
1755
|
-
for (const ext of exts)
|
|
1947
|
+
for (const ext of exts)
|
|
1948
|
+
add(
|
|
1949
|
+
`<Default Extension="${ext}" ContentType="image/${ext === "jpg" ? "jpeg" : ext}"/>`,
|
|
1950
|
+
ext
|
|
1951
|
+
);
|
|
1756
1952
|
if (hasComments) {
|
|
1757
|
-
add(
|
|
1758
|
-
|
|
1953
|
+
add(
|
|
1954
|
+
'<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>',
|
|
1955
|
+
"/word/comments.xml"
|
|
1956
|
+
);
|
|
1957
|
+
add(
|
|
1958
|
+
'<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"/>',
|
|
1959
|
+
"/word/commentsExtended.xml"
|
|
1960
|
+
);
|
|
1759
1961
|
}
|
|
1760
1962
|
return out;
|
|
1761
1963
|
}
|
|
1762
1964
|
function extractBodySectPr(xml) {
|
|
1763
|
-
const all = xml.match(
|
|
1965
|
+
const all = xml.match(
|
|
1966
|
+
/<w:sectPr\b[^>]*>[\s\S]*?<\/w:sectPr>|<w:sectPr\b[^>]*\/>/g
|
|
1967
|
+
);
|
|
1764
1968
|
return all ? all[all.length - 1] : "";
|
|
1765
1969
|
}
|
|
1766
1970
|
function mergeRels(xml, newRels) {
|
|
@@ -1769,7 +1973,10 @@ function mergeRels(xml, newRels) {
|
|
|
1769
1973
|
/<Relationship\b[^>]*Target="comments(?:Extended)?\.xml"[^>]*\/>/g,
|
|
1770
1974
|
""
|
|
1771
1975
|
);
|
|
1772
|
-
return base.replace(
|
|
1976
|
+
return base.replace(
|
|
1977
|
+
"</Relationships>",
|
|
1978
|
+
`${newRels.join("")}</Relationships>`
|
|
1979
|
+
);
|
|
1773
1980
|
}
|
|
1774
1981
|
async function exportDocx(doc, opts) {
|
|
1775
1982
|
const comments = doc.attrs["comments"] ?? [];
|
|
@@ -1778,7 +1985,8 @@ async function exportDocx(doc, opts) {
|
|
|
1778
1985
|
let idx = 0;
|
|
1779
1986
|
doc.descendants((n) => {
|
|
1780
1987
|
if (!isInlineLeaf(n)) return;
|
|
1781
|
-
for (const id of commentIdsOf(n))
|
|
1988
|
+
for (const id of commentIdsOf(n))
|
|
1989
|
+
if (knownComments.has(id)) lastRun.set(id, idx);
|
|
1782
1990
|
idx++;
|
|
1783
1991
|
});
|
|
1784
1992
|
const ctx = {
|
|
@@ -1793,13 +2001,20 @@ async function exportDocx(doc, opts) {
|
|
|
1793
2001
|
};
|
|
1794
2002
|
const boundaries = sectionBoundaries(doc);
|
|
1795
2003
|
let body = "";
|
|
1796
|
-
doc.forEach(
|
|
2004
|
+
doc.forEach(
|
|
2005
|
+
(block, _offset, i) => body += blockXml(block, ctx, boundaries.get(i))
|
|
2006
|
+
);
|
|
1797
2007
|
const hasComments = comments.length > 0;
|
|
1798
2008
|
if (hasComments) {
|
|
1799
|
-
ctx.rels.push(
|
|
1800
|
-
|
|
2009
|
+
ctx.rels.push(
|
|
2010
|
+
`<Relationship Id="rIdComments" Type="${R_NS}/comments" Target="comments.xml"/>`
|
|
2011
|
+
);
|
|
2012
|
+
ctx.rels.push(
|
|
2013
|
+
`<Relationship Id="rIdCommentsExt" Type="${R_NS}/commentsExtended" Target="commentsExtended.xml"/>`
|
|
2014
|
+
);
|
|
1801
2015
|
}
|
|
1802
2016
|
const zip = new import_jszip2.default();
|
|
2017
|
+
const styleIds = usedStyleIds(doc);
|
|
1803
2018
|
let sectPr = "";
|
|
1804
2019
|
if (opts?.carry) {
|
|
1805
2020
|
const carry = opts.carry;
|
|
@@ -1807,18 +2022,29 @@ async function exportDocx(doc, opts) {
|
|
|
1807
2022
|
if (!f.dir) zip.file(path, await f.async("uint8array"));
|
|
1808
2023
|
}
|
|
1809
2024
|
const ct = await carry.file("[Content_Types].xml")?.async("string");
|
|
1810
|
-
zip.file(
|
|
2025
|
+
zip.file(
|
|
2026
|
+
"[Content_Types].xml",
|
|
2027
|
+
ct ? mergeContentTypes(ct, ctx.exts, hasComments) : contentTypes(ctx.exts, hasComments)
|
|
2028
|
+
);
|
|
2029
|
+
const carriedStyles = await carry.file("word/styles.xml")?.async("string");
|
|
2030
|
+
if (carriedStyles)
|
|
2031
|
+
zip.file("word/styles.xml", mergeStyles(carriedStyles, styleIds));
|
|
1811
2032
|
const rels = await carry.file("word/_rels/document.xml.rels")?.async("string");
|
|
1812
2033
|
zip.file("word/_rels/document.xml.rels", mergeRels(rels, ctx.rels));
|
|
1813
2034
|
const origDoc = await carry.file("word/document.xml")?.async("string");
|
|
1814
2035
|
if (origDoc) sectPr = extractBodySectPr(origDoc);
|
|
1815
2036
|
} else {
|
|
2037
|
+
ctx.rels.push(
|
|
2038
|
+
`<Relationship Id="rIdStyles" Type="${R_NS}/styles" Target="styles.xml"/>`
|
|
2039
|
+
);
|
|
2040
|
+
zip.file("word/styles.xml", stylesXml(styleIds));
|
|
1816
2041
|
zip.file("[Content_Types].xml", contentTypes(ctx.exts, hasComments));
|
|
1817
2042
|
zip.file("_rels/.rels", ROOT_RELS);
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
2043
|
+
zip.file(
|
|
2044
|
+
"word/_rels/document.xml.rels",
|
|
2045
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2046
|
+
<Relationships xmlns="${PR_NS}">${ctx.rels.join("")}</Relationships>`
|
|
2047
|
+
);
|
|
1822
2048
|
}
|
|
1823
2049
|
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1824
2050
|
<w:document xmlns:w="${W_NS}" xmlns:r="${R_NS}" xmlns:wp="${WP_NS}" xmlns:a="${A_NS}" xmlns:pic="${PIC_NS}" xmlns:wps="${WPS_NS}"><w:body>${body}${sectPr}</w:body></w:document>`;
|
|
@@ -1827,7 +2053,8 @@ async function exportDocx(doc, opts) {
|
|
|
1827
2053
|
zip.file("word/comments.xml", commentsXml(comments));
|
|
1828
2054
|
zip.file("word/commentsExtended.xml", commentsExtendedXml(comments));
|
|
1829
2055
|
}
|
|
1830
|
-
for (const { path, base64 } of ctx.media)
|
|
2056
|
+
for (const { path, base64 } of ctx.media)
|
|
2057
|
+
zip.file(path, base64, { base64: true });
|
|
1831
2058
|
return zip.generateAsync({ type: "uint8array" });
|
|
1832
2059
|
}
|
|
1833
2060
|
// Annotate the CommonJS export names for ESM import in node:
|