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.
- package/README.md +12 -6
- package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
- package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
- package/dist/esm/core/bytes.d.ts +1 -0
- package/dist/esm/core/bytes.js +6 -1
- package/dist/esm/core/converter/facade.d.ts +2 -2
- package/dist/esm/core/converter/facade.js +12 -0
- package/dist/esm/core/converter/project.js +2 -0
- package/dist/esm/core/converter/ream.d.ts +1 -1
- package/dist/esm/core/converter/ream.js +10 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +58 -0
- package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +1 -1
- package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
- package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
- package/dist/esm/core/drawingml/shape-render.js +71 -0
- package/dist/esm/core/ir/features.d.ts +1 -0
- package/dist/esm/core/ir/features.js +1 -0
- package/dist/esm/core/ir/flow.d.ts +3 -0
- package/dist/esm/core/links.d.ts +6 -0
- package/dist/esm/core/links.js +19 -0
- package/dist/esm/core/numbering/apply.js +3 -1
- package/dist/esm/core/style-cascade/index.d.ts +1 -0
- package/dist/esm/core/style-cascade/index.js +1 -0
- package/dist/esm/core/style-cascade/table.d.ts +2 -0
- package/dist/esm/core/style-cascade/table.js +161 -0
- package/dist/esm/core/vector.d.ts +2 -0
- package/dist/esm/core/vector.js +19 -1
- package/dist/esm/html/html-writer.d.ts +4 -0
- package/dist/esm/html/html-writer.js +464 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +3 -0
- package/dist/esm/layout/styled-layout.d.ts +19 -3
- package/dist/esm/layout/styled-layout.js +533 -197
- package/dist/esm/pdf/struct-tree.d.ts +7 -1
- package/dist/esm/pdf/struct-tree.js +22 -6
- package/dist/esm/pdf/styled-page-emitter.d.ts +1 -1
- package/dist/esm/pdf/styled-page-emitter.js +161 -29
- package/dist/esm/pdf/xmp.d.ts +1 -0
- package/dist/esm/pdf/xmp.js +4 -0
- package/dist/esm/svg/svg-writer.js +3 -11
- package/dist/esm/word/document-parser.d.ts +3 -0
- package/dist/esm/word/document-parser.js +210 -23
- package/dist/esm/word/docx-reader.js +30 -4
- package/dist/esm/word/drawing-parser.d.ts +4 -1
- package/dist/esm/word/drawing-parser.js +53 -2
- package/dist/esm/word/index.d.ts +2 -2
- package/dist/esm/word/styles-parser.js +134 -1
- package/dist/esm/word/table-parser.js +35 -0
- package/package.json +1 -1
- /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
|
-
|
|
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
|
|
212
|
-
collectRuns(p,
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
|
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) {
|
package/dist/esm/word/index.d.ts
CHANGED
|
@@ -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 };
|