@stll/folio-core 0.25.4 → 0.26.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/docx/compatibility.js +2 -2
- package/dist/docx/runParser.js +3 -2
- package/dist/docx/serializer/paragraphSerializer.js +1 -1
- package/dist/docx/serializer/runSerializer.js +6 -2
- package/dist/docx/serializer/sectionPropertiesSerializer.js +3 -3
- package/dist/docx/server/createBilingualDocument.d.ts +10 -5
- package/dist/docx/server/createBilingualDocument.js +39 -9
- package/dist/docx/server/createBilingualDocx.d.ts +3 -2
- package/dist/docx/server/createBilingualDocx.js +13 -4
- package/dist/docx/shapeParser.js +26 -3
- package/dist/docx/unzip.js +4 -4
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -7
- package/dist/prosemirror/attrs/index.js +9 -1
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +26 -6
- package/dist/prosemirror/conversion/toProseDoc.js +17 -6
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +15 -3
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +6 -1
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +55 -3
- package/dist/prosemirror/schema/nodes.d.ts +6 -0
- package/dist/prosemirror/shapeGeometryAdjustments.d.ts +5 -0
- package/dist/prosemirror/shapeGeometryAdjustments.js +24 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +5 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +4 -2
- package/dist/redline.js +13 -6
- package/dist/redlineOperationLimit.d.ts +8 -0
- package/dist/redlineOperationLimit.js +6 -0
- package/dist/server.d.ts +2 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/index.d.ts +3 -1
- package/dist/utils/tableOfContentsStyle.d.ts +9 -0
- package/dist/utils/tableOfContentsStyle.js +14 -0
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
|
|
1
|
+
import { DOCX_CONFORMANCE_CLASSES, DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
2
2
|
//#region src/docx/compatibility.ts
|
|
3
3
|
const resolveCompatibilityContext = (doc, options) => ({
|
|
4
4
|
host: options.host ?? "unknown",
|
|
@@ -146,7 +146,7 @@ function inspectHyperlink(hyperlink, context) {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
function inspectRun(run, context) {
|
|
149
|
-
for (const [contentIndex, content] of run.content.entries()) if (content.type === "drawing" && content.rawXml) context.record({
|
|
149
|
+
for (const [contentIndex, content] of run.content.entries()) if (content.type === "drawing" && content.rawXml && content.rawXmlMode !== DRAWING_RAW_XML_MODES.PRESERVE_ONLY) context.record({
|
|
150
150
|
...context.blockId === void 0 ? {} : { blockId: context.blockId },
|
|
151
151
|
part: context.part,
|
|
152
152
|
path: `${context.path}.content[${contentIndex}]`
|
package/dist/docx/runParser.js
CHANGED
|
@@ -7,7 +7,7 @@ import { requiresXmlSpacePreserve } from "./textWhitespace.js";
|
|
|
7
7
|
import { resolveThemeFontRef } from "./themeParser.js";
|
|
8
8
|
import { parseVmlImageContent } from "./vmlImageParser.js";
|
|
9
9
|
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, findChildren, getAttribute, getChildElements, getLocalName, getTextContent, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
10
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
10
|
+
import { DRAWING_RAW_XML_MODES, normalizeRevisionId } from "@stll/docx-core/model";
|
|
11
11
|
//#region src/docx/runParser.ts
|
|
12
12
|
/**
|
|
13
13
|
* Sanity cap on `w:lang` `@w:val`/`@w:eastAsia`/`@w:bidi` tag length. BCP-47
|
|
@@ -500,7 +500,8 @@ function parseDrawingContent(element, rels, media) {
|
|
|
500
500
|
},
|
|
501
501
|
wrap: { type: "inline" }
|
|
502
502
|
},
|
|
503
|
-
rawXml: elementToXml(element)
|
|
503
|
+
rawXml: elementToXml(element),
|
|
504
|
+
rawXmlMode: DRAWING_RAW_XML_MODES.PRESERVE_ONLY
|
|
504
505
|
};
|
|
505
506
|
const shape = parseShapeFromDrawing(element);
|
|
506
507
|
if (shape) return {
|
|
@@ -215,7 +215,7 @@ function serializeParagraphPropertyChange(change) {
|
|
|
215
215
|
*/
|
|
216
216
|
function serializeHyperlink(hyperlink) {
|
|
217
217
|
const attrs = [];
|
|
218
|
-
if (hyperlink.rId) attrs.push(`r:id="${hyperlink.rId}"`);
|
|
218
|
+
if (hyperlink.rId) attrs.push(`r:id="${escapeXml(hyperlink.rId)}"`);
|
|
219
219
|
if (hyperlink.anchor) attrs.push(`w:anchor="${escapeXml(hyperlink.anchor)}"`);
|
|
220
220
|
if (hyperlink.tooltip) attrs.push(`w:tooltip="${escapeXml(hyperlink.tooltip)}"`);
|
|
221
221
|
if (hyperlink.target) attrs.push(`w:tgtFrame="${escapeXml(hyperlink.target)}"`);
|
|
@@ -338,7 +338,7 @@ function serializeWrap(wrap) {
|
|
|
338
338
|
function serializePicGraphic(image, sharedId) {
|
|
339
339
|
const cx = image.size.width;
|
|
340
340
|
const cy = image.size.height;
|
|
341
|
-
const rId = image.rId || "rId1";
|
|
341
|
+
const rId = escapeXml(image.rId || "rId1");
|
|
342
342
|
const id = sharedId;
|
|
343
343
|
const name = image.filename || `image${id}`;
|
|
344
344
|
let xfrmAttrs = "";
|
|
@@ -448,6 +448,10 @@ function serializeDrawingContent(content) {
|
|
|
448
448
|
function serializeShapeTextBody(blocks) {
|
|
449
449
|
return blocks.map((block) => block.type === "paragraph" ? serializeParagraph(block) : serializeTable(block, serializeParagraph)).join("");
|
|
450
450
|
}
|
|
451
|
+
function serializeGeometryAdjustments(shape) {
|
|
452
|
+
if (!shape.geometryAdjustments || shape.geometryAdjustments.length === 0) return "<a:avLst/>";
|
|
453
|
+
return `<a:avLst>${shape.geometryAdjustments.map(({ name, formula }) => `<a:gd name="${escapeXml(name)}" fmla="${escapeXml(formula)}"/>`).join("")}</a:avLst>`;
|
|
454
|
+
}
|
|
451
455
|
/**
|
|
452
456
|
* Serialize shape content to full DrawingML XML (wps:wsp inside w:drawing)
|
|
453
457
|
*/
|
|
@@ -470,7 +474,7 @@ function serializeShapeContent(content) {
|
|
|
470
474
|
"<a:off x=\"0\" y=\"0\"/>",
|
|
471
475
|
`<a:ext cx="${intAttr(cx)}" cy="${intAttr(cy)}"/>`,
|
|
472
476
|
"</a:xfrm>",
|
|
473
|
-
`<a:prstGeom prst="${shape.shapeType === "textBox" ? "rect" : shape.shapeType}"
|
|
477
|
+
`<a:prstGeom prst="${shape.shapeType === "textBox" ? "rect" : shape.shapeType}">${serializeGeometryAdjustments(shape)}</a:prstGeom>`,
|
|
474
478
|
serializeFill(shape.fill),
|
|
475
479
|
serializeOutline(shape.outline),
|
|
476
480
|
"</wps:spPr>"
|
|
@@ -3,8 +3,8 @@ import { serializeBorder } from "./borderSerializer.js";
|
|
|
3
3
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
4
|
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
5
|
//#region src/docx/serializer/sectionPropertiesSerializer.ts
|
|
6
|
-
const serializeHeaderReference = (ref) => `<w:headerReference w:type="${ref.type}" r:id="${ref.rId}"/>`;
|
|
7
|
-
const serializeFooterReference = (ref) => `<w:footerReference w:type="${ref.type}" r:id="${ref.rId}"/>`;
|
|
6
|
+
const serializeHeaderReference = (ref) => `<w:headerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
7
|
+
const serializeFooterReference = (ref) => `<w:footerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
8
8
|
function serializeFootnoteProperties(props) {
|
|
9
9
|
if (!props) return "";
|
|
10
10
|
const parts = [];
|
|
@@ -178,7 +178,7 @@ function serializeSectionProperties(props) {
|
|
|
178
178
|
serializeOnOffElement(props.noEndnote, "noEndnote"),
|
|
179
179
|
serializeOnOffElement(props.rtlGutter, "rtlGutter")
|
|
180
180
|
]) if (xml) parts.push(xml);
|
|
181
|
-
if (props.printerSettingsRelationshipId) parts.push(`<w:printerSettings r:id="${props.printerSettingsRelationshipId}"/>`);
|
|
181
|
+
if (props.printerSettingsRelationshipId) parts.push(`<w:printerSettings r:id="${escapeXml(props.printerSettingsRelationshipId)}"/>`);
|
|
182
182
|
for (const change of props.propertyChanges ?? []) parts.push(serializeSectionPropertyChange(change));
|
|
183
183
|
const unserializedChildNames = getUnserializedSectionPropertyChildNames(props);
|
|
184
184
|
if (unserializedChildNames && unserializedChildNames.length > 0) return "";
|
|
@@ -37,6 +37,11 @@ type CreateBilingualDocumentOptions = {
|
|
|
37
37
|
targetStyleSuffix: string;
|
|
38
38
|
/** Table borders; legal practice is usually `"none"`. Default `"none"`. */
|
|
39
39
|
borders?: BilingualBorders;
|
|
40
|
+
/**
|
|
41
|
+
* Paragraph handles exposed by Folio's canonical AI-edit snapshot for the
|
|
42
|
+
* source DOCX. Only these paragraphs may become translation rows.
|
|
43
|
+
*/
|
|
44
|
+
editableParagraphIds: ReadonlySet<string>;
|
|
40
45
|
};
|
|
41
46
|
type CreateBilingualDocumentResult = {
|
|
42
47
|
document: document_d_exports.Document;
|
|
@@ -52,11 +57,11 @@ declare class InvalidBilingualDocumentOptionsError extends InvalidBilingualDocum
|
|
|
52
57
|
declare function createBilingualDocument(source: document_d_exports.Document, options: CreateBilingualDocumentOptions): CreateBilingualDocumentResult;
|
|
53
58
|
/**
|
|
54
59
|
* Re-derive the row manifest from a document produced by
|
|
55
|
-
* {@link createBilingualDocument}.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* right paragraph's `paraId` is the row handle
|
|
60
|
+
* {@link createBilingualDocument}. A dedicated table-style discriminator keeps
|
|
61
|
+
* ordinary two-column source tables from being mistaken for bilingual output;
|
|
62
|
+
* the expected row structure is validated as a second check. Rows are returned
|
|
63
|
+
* in document order; the right paragraph's `paraId` is the row handle.
|
|
59
64
|
*/
|
|
60
|
-
declare function readBilingualDocument(document: document_d_exports.Document): BilingualRow[];
|
|
65
|
+
declare function readBilingualDocument(document: document_d_exports.Document, editableParagraphIds: ReadonlySet<string>): BilingualRow[];
|
|
61
66
|
//#endregion
|
|
62
67
|
export { BilingualBorders, BilingualParagraphRef, BilingualRow, BilingualRowKind, BilingualTableParagraphRef, CreateBilingualDocumentOptions, CreateBilingualDocumentResult, InvalidBilingualDocumentOptionsError, createBilingualDocument, readBilingualDocument };
|
|
@@ -17,13 +17,17 @@ import { TaggedError } from "better-result";
|
|
|
17
17
|
* and the break paragraph stays between the tables. A source table (parties,
|
|
18
18
|
* signature block) is kept once, in a row spanning both columns: it is signed
|
|
19
19
|
* and read once, and its labels are translated inline rather than duplicated.
|
|
20
|
+
* Structural-only paragraphs are also kept once between tables; they have no
|
|
21
|
+
* independently editable text for a translation row to address.
|
|
20
22
|
*/
|
|
21
23
|
const STYLE_SUFFIX_PATTERN = /^[A-Za-z0-9-]+$/u;
|
|
22
24
|
var InvalidBilingualDocumentOptionsError = class extends TaggedError("InvalidBilingualDocumentOptionsError") {};
|
|
25
|
+
var UneditableBilingualManifestError = class extends TaggedError("UneditableBilingualManifestError") {};
|
|
23
26
|
const FULL_WIDTH_PCT = 5e3;
|
|
24
27
|
const HALF_WIDTH_PCT = 2500;
|
|
25
28
|
const A4_TEXT_WIDTH_TWIPS = 9072;
|
|
26
29
|
const ROW_ID_NAMESPACE = "folio-bilingual";
|
|
30
|
+
const BILINGUAL_TABLE_STYLE_ID = "FolioBilingualTranslation";
|
|
27
31
|
const GRID_BORDER = {
|
|
28
32
|
style: "single",
|
|
29
33
|
size: 4,
|
|
@@ -96,6 +100,11 @@ function createBilingualDocument(source, options) {
|
|
|
96
100
|
}
|
|
97
101
|
if (block.type === "paragraph") {
|
|
98
102
|
if (isEmptyParagraph(block)) continue;
|
|
103
|
+
if (block.paraId === void 0 || !options.editableParagraphIds.has(block.paraId)) {
|
|
104
|
+
flushSection();
|
|
105
|
+
content.push(block);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
99
108
|
const { copy, ref } = copyParagraph(block);
|
|
100
109
|
rows.push({
|
|
101
110
|
kind: classifyParagraph(block, styleById),
|
|
@@ -105,10 +114,15 @@ function createBilingualDocument(source, options) {
|
|
|
105
114
|
sectionRows.push(buildRow(block, copy));
|
|
106
115
|
continue;
|
|
107
116
|
}
|
|
108
|
-
const paragraphs = collectTableParagraphs(block).map((paragraph) => ({
|
|
117
|
+
const paragraphs = collectTableParagraphs(block).filter((paragraph) => paragraph.paraId !== void 0 && options.editableParagraphIds.has(paragraph.paraId)).map((paragraph) => ({
|
|
109
118
|
paraId: paragraph.paraId,
|
|
110
119
|
sourceText: getParagraphText(paragraph)
|
|
111
120
|
}));
|
|
121
|
+
if (paragraphs.length === 0) {
|
|
122
|
+
flushSection();
|
|
123
|
+
content.push(block);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
112
126
|
rows.push({
|
|
113
127
|
kind: "table",
|
|
114
128
|
rowId: paragraphs.at(0)?.paraId ?? tableRowHandle(rows.length),
|
|
@@ -152,7 +166,7 @@ const flattenBlocks = (content) => {
|
|
|
152
166
|
};
|
|
153
167
|
const isEmptyParagraph = (paragraph) => {
|
|
154
168
|
if (getParagraphText(paragraph).trim().length > 0) return false;
|
|
155
|
-
return paragraph.content.every((item) => item.type === "run" && item.content.every((part) => part.type === "text"));
|
|
169
|
+
return paragraph.content.every((item) => item.type === "run" && item.formatting?.hidden !== true && item.content.every((part) => part.type === "text"));
|
|
156
170
|
};
|
|
157
171
|
/** Heading style families across Word UI languages (en, cs/sk, de, fr, pl). */
|
|
158
172
|
const HEADING_STYLE_PATTERN = /heading|nadpis|berschrift|titre|nag[łl]/iu;
|
|
@@ -391,6 +405,7 @@ const buildTable = (rows, borders, textWidth) => ({
|
|
|
391
405
|
value: FULL_WIDTH_PCT,
|
|
392
406
|
type: "pct"
|
|
393
407
|
},
|
|
408
|
+
styleId: BILINGUAL_TABLE_STYLE_ID,
|
|
394
409
|
layout: "fixed",
|
|
395
410
|
borders: TABLE_BORDERS[borders],
|
|
396
411
|
look: {
|
|
@@ -453,21 +468,22 @@ const createParaIdMinter = (taken) => {
|
|
|
453
468
|
};
|
|
454
469
|
/**
|
|
455
470
|
* Re-derive the row manifest from a document produced by
|
|
456
|
-
* {@link createBilingualDocument}.
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
* right paragraph's `paraId` is the row handle
|
|
471
|
+
* {@link createBilingualDocument}. A dedicated table-style discriminator keeps
|
|
472
|
+
* ordinary two-column source tables from being mistaken for bilingual output;
|
|
473
|
+
* the expected row structure is validated as a second check. Rows are returned
|
|
474
|
+
* in document order; the right paragraph's `paraId` is the row handle.
|
|
460
475
|
*/
|
|
461
|
-
function readBilingualDocument(document) {
|
|
476
|
+
function readBilingualDocument(document, editableParagraphIds) {
|
|
462
477
|
const styleById = new Map((document.package.styles?.styles ?? []).map((style) => [style.styleId, style]));
|
|
463
478
|
const rows = [];
|
|
479
|
+
let missingHandleCount = 0;
|
|
464
480
|
for (const block of flattenBlocks(document.package.document.content)) {
|
|
465
481
|
if (block.type !== "table" || !isBilingualTable(block)) continue;
|
|
466
482
|
for (const row of block.rows) {
|
|
467
483
|
const [left, right] = row.cells;
|
|
468
484
|
if (!left) continue;
|
|
469
485
|
if (!right) {
|
|
470
|
-
const paragraphs = left.content.filter((item) => item.type === "table").flatMap(collectTableParagraphs).map((paragraph) => ({
|
|
486
|
+
const paragraphs = left.content.filter((item) => item.type === "table").flatMap(collectTableParagraphs).filter((paragraph) => paragraph.paraId !== void 0 && editableParagraphIds.has(paragraph.paraId)).map((paragraph) => ({
|
|
471
487
|
paraId: paragraph.paraId,
|
|
472
488
|
sourceText: getParagraphText(paragraph)
|
|
473
489
|
}));
|
|
@@ -480,7 +496,16 @@ function readBilingualDocument(document) {
|
|
|
480
496
|
}
|
|
481
497
|
const source = left.content.at(0);
|
|
482
498
|
const target = right.content.at(0);
|
|
483
|
-
if (source?.type !== "paragraph" || target?.type !== "paragraph"
|
|
499
|
+
if (source?.type !== "paragraph" || target?.type !== "paragraph") continue;
|
|
500
|
+
if (target.paraId === void 0) {
|
|
501
|
+
missingHandleCount += 1;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const sourceMissing = source.paraId === void 0 || !editableParagraphIds.has(source.paraId);
|
|
505
|
+
const targetMissing = !editableParagraphIds.has(target.paraId);
|
|
506
|
+
if (sourceMissing) missingHandleCount += 1;
|
|
507
|
+
if (targetMissing) missingHandleCount += 1;
|
|
508
|
+
if (sourceMissing || targetMissing) continue;
|
|
484
509
|
rows.push({
|
|
485
510
|
kind: classifyParagraph(source, styleById),
|
|
486
511
|
rowId: target.paraId,
|
|
@@ -490,9 +515,14 @@ function readBilingualDocument(document) {
|
|
|
490
515
|
});
|
|
491
516
|
}
|
|
492
517
|
}
|
|
518
|
+
if (missingHandleCount > 0) throw new UneditableBilingualManifestError({
|
|
519
|
+
message: "Bilingual manifest contains handles absent from the Folio AI-edit snapshot.",
|
|
520
|
+
missingHandleCount
|
|
521
|
+
});
|
|
493
522
|
return rows;
|
|
494
523
|
}
|
|
495
524
|
const isBilingualTable = (table) => {
|
|
525
|
+
if (table.formatting?.styleId !== BILINGUAL_TABLE_STYLE_ID) return false;
|
|
496
526
|
let pairs = 0;
|
|
497
527
|
for (const row of table.rows) {
|
|
498
528
|
const cells = row.cells;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BilingualRow, CreateBilingualDocumentOptions } from "./createBilingualDocument.js";
|
|
2
2
|
//#region src/docx/server/createBilingualDocx.d.ts
|
|
3
|
+
type CreateBilingualDocxOptions = Omit<CreateBilingualDocumentOptions, "editableParagraphIds">;
|
|
3
4
|
type CreateBilingualDocxResult = {
|
|
4
5
|
buffer: ArrayBuffer;
|
|
5
6
|
rows: BilingualRow[];
|
|
@@ -12,8 +13,8 @@ type CreateBilingualDocxResult = {
|
|
|
12
13
|
* as a two-column table, and repack onto the original package so theme, fonts,
|
|
13
14
|
* media, headers and footers carry over untouched.
|
|
14
15
|
*/
|
|
15
|
-
declare function createBilingualDocx(input: ArrayBuffer | Uint8Array, options:
|
|
16
|
+
declare function createBilingualDocx(input: ArrayBuffer | Uint8Array, options: CreateBilingualDocxOptions): Promise<CreateBilingualDocxResult>;
|
|
16
17
|
/** Bytes-in form of {@link readBilingualDocument}. */
|
|
17
18
|
declare function readBilingualDocx(input: ArrayBuffer | Uint8Array): Promise<BilingualRow[]>;
|
|
18
19
|
//#endregion
|
|
19
|
-
export { CreateBilingualDocxResult, createBilingualDocx, readBilingualDocx };
|
|
20
|
+
export { CreateBilingualDocxOptions, CreateBilingualDocxResult, createBilingualDocx, readBilingualDocx };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { FolioDocxReviewer } from "../../ai-edits/headless.js";
|
|
2
|
+
import { toArrayBuffer } from "../../utils/docxInput.js";
|
|
1
3
|
import { ensureParaIds } from "../ensureParaIds.js";
|
|
2
4
|
import { parseDocx } from "../parser.js";
|
|
3
5
|
import { createDocx } from "../rezip.js";
|
|
@@ -11,16 +13,23 @@ import { createBilingualDocument, readBilingualDocument } from "./createBilingua
|
|
|
11
13
|
* media, headers and footers carry over untouched.
|
|
12
14
|
*/
|
|
13
15
|
async function createBilingualDocx(input, options) {
|
|
14
|
-
const
|
|
16
|
+
const stampedBuffer = await toArrayBuffer((await ensureParaIds(input)).docx);
|
|
17
|
+
const editableParagraphIds = new Set((await FolioDocxReviewer.fromBuffer(stampedBuffer)).snapshot().blocks.map(({ id }) => id));
|
|
18
|
+
const { document, warnings } = createBilingualDocument(await parseDocx(stampedBuffer, { preloadFonts: false }), {
|
|
19
|
+
...options,
|
|
20
|
+
editableParagraphIds
|
|
21
|
+
});
|
|
22
|
+
const buffer = await createDocx(document);
|
|
15
23
|
return {
|
|
16
|
-
buffer
|
|
17
|
-
rows,
|
|
24
|
+
buffer,
|
|
25
|
+
rows: await readBilingualDocx(buffer),
|
|
18
26
|
warnings
|
|
19
27
|
};
|
|
20
28
|
}
|
|
21
29
|
/** Bytes-in form of {@link readBilingualDocument}. */
|
|
22
30
|
async function readBilingualDocx(input) {
|
|
23
|
-
|
|
31
|
+
const buffer = await toArrayBuffer(input);
|
|
32
|
+
return readBilingualDocument(await parseDocx(buffer, { preloadFonts: false }), new Set((await FolioDocxReviewer.fromBuffer(buffer)).snapshot().blocks.map(({ id }) => id)));
|
|
24
33
|
}
|
|
25
34
|
//#endregion
|
|
26
35
|
export { createBilingualDocx, readBilingualDocx };
|
package/dist/docx/shapeParser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseAnchorPosition, parseAnchorWrap, parseFill, parseOutline } from "./drawingUtils.js";
|
|
2
2
|
import { ShapeTypeSchema, narrowEnum } from "./parserEnums.js";
|
|
3
|
-
import { findAllDeep, findChildByLocalName, getAttribute, parseNumericAttribute } from "./xmlParser.js";
|
|
3
|
+
import { findAllDeep, findChildByLocalName, findChildren, getAttribute, getChildElements, parseNumericAttribute } from "./xmlParser.js";
|
|
4
4
|
//#region src/docx/shapeParser.ts
|
|
5
5
|
/** Convert OOXML rotation (1/60000ths of a degree) to degrees. */
|
|
6
6
|
function rotToDegrees(rot) {
|
|
@@ -56,8 +56,29 @@ function hasUnsupportedGeometry(spPr) {
|
|
|
56
56
|
if (!spPr) return false;
|
|
57
57
|
const prstGeom = findChildByLocalName(spPr, "prstGeom");
|
|
58
58
|
if (!prstGeom) return findChildByLocalName(spPr, "custGeom") !== null;
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const avLst = findChildByLocalName(prstGeom, "avLst");
|
|
60
|
+
const prst = getAttribute(prstGeom, null, "prst");
|
|
61
|
+
if (narrowEnum(prst, ShapeTypeSchema) === void 0) return true;
|
|
62
|
+
const adjustmentChildren = avLst ? getChildElements(avLst) : [];
|
|
63
|
+
if (adjustmentChildren.length === 0) return false;
|
|
64
|
+
const adjustments = findChildren(avLst, "a", "gd");
|
|
65
|
+
const adjustmentNames = new Set(adjustments.map((adjustment) => getAttribute(adjustment, null, "name")));
|
|
66
|
+
return !(prst === "rightBrace" && adjustments.length === 2 && adjustmentChildren.length === adjustments.length && adjustmentNames.size === 2 && adjustmentNames.has("adj1") && adjustmentNames.has("adj2") && adjustments.every((adjustment) => /^val\s+-?\d+$/u.test(getAttribute(adjustment, null, "fmla") ?? "")));
|
|
67
|
+
}
|
|
68
|
+
function parseGeometryAdjustments(spPr) {
|
|
69
|
+
const prstGeom = spPr ? findChildByLocalName(spPr, "prstGeom") : null;
|
|
70
|
+
const avLst = prstGeom ? findChildByLocalName(prstGeom, "avLst") : null;
|
|
71
|
+
if (!avLst) return;
|
|
72
|
+
const adjustments = [];
|
|
73
|
+
for (const adjustment of findChildren(avLst, "a", "gd")) {
|
|
74
|
+
const name = getAttribute(adjustment, null, "name");
|
|
75
|
+
const formula = getAttribute(adjustment, null, "fmla");
|
|
76
|
+
if (name !== null && formula !== null) adjustments.push({
|
|
77
|
+
name,
|
|
78
|
+
formula
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return adjustments.length === 0 ? void 0 : adjustments;
|
|
61
82
|
}
|
|
62
83
|
function hasUnsupportedRgbColorModifiers(spPr) {
|
|
63
84
|
for (const color of findAllDeep(spPr, "a", "srgbClr")) if (color.elements?.some((child) => child.type === "element")) return true;
|
|
@@ -94,6 +115,8 @@ function parseShape(node) {
|
|
|
94
115
|
shapeType,
|
|
95
116
|
size
|
|
96
117
|
};
|
|
118
|
+
const geometryAdjustments = parseGeometryAdjustments(spPr);
|
|
119
|
+
if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
|
|
97
120
|
if (id !== void 0) shape.id = id;
|
|
98
121
|
if (name !== void 0) shape.name = name;
|
|
99
122
|
if (fill !== void 0) shape.fill = fill;
|
package/dist/docx/unzip.js
CHANGED
|
@@ -147,7 +147,7 @@ async function unzipDocx(buffer, options = {}) {
|
|
|
147
147
|
if (lowerPath.endsWith(".xml") || lowerPath.endsWith(".rels")) {
|
|
148
148
|
assertEntrySize(path, declaredSize, limits.maxXmlBytes);
|
|
149
149
|
if (options.extractAllXml === false && !shouldExtractXmlPart(lowerPath)) continue;
|
|
150
|
-
extractionTasks.push(file.async("text").then((xmlContent) => {
|
|
150
|
+
extractionTasks.push(() => file.async("text").then((xmlContent) => {
|
|
151
151
|
assertExtractedSize(path, xmlContent.length, limits.maxXmlBytes);
|
|
152
152
|
return {
|
|
153
153
|
type: "xml",
|
|
@@ -163,7 +163,7 @@ async function unzipDocx(buffer, options = {}) {
|
|
|
163
163
|
content.warnings.push(`Skipped oversized media file: ${path}; original entry preserved for round-trip.`);
|
|
164
164
|
continue;
|
|
165
165
|
}
|
|
166
|
-
extractionTasks.push(file.async("arraybuffer").then((binaryContent) => {
|
|
166
|
+
extractionTasks.push(() => file.async("arraybuffer").then((binaryContent) => {
|
|
167
167
|
if (binaryContent.byteLength > limits.maxMediaBytes) {
|
|
168
168
|
content.warnings.push(`Skipped oversized media file: ${path}; original entry preserved for round-trip.`);
|
|
169
169
|
return null;
|
|
@@ -178,7 +178,7 @@ async function unzipDocx(buffer, options = {}) {
|
|
|
178
178
|
}));
|
|
179
179
|
} else if (lowerPath.startsWith("word/fonts/")) {
|
|
180
180
|
if (isEntryTooLarge(declaredSize, limits.maxFontBytes)) continue;
|
|
181
|
-
extractionTasks.push(file.async("arraybuffer").then((binaryContent) => {
|
|
181
|
+
extractionTasks.push(() => file.async("arraybuffer").then((binaryContent) => {
|
|
182
182
|
if (binaryContent.byteLength > limits.maxFontBytes) return null;
|
|
183
183
|
return {
|
|
184
184
|
type: "font",
|
|
@@ -188,7 +188,7 @@ async function unzipDocx(buffer, options = {}) {
|
|
|
188
188
|
}));
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
|
-
for (const extracted of await Promise.all(extractionTasks)) {
|
|
191
|
+
for (const extracted of await Promise.all(extractionTasks.map((extract) => extract()))) {
|
|
192
192
|
if (!extracted) continue;
|
|
193
193
|
if (extracted.type === "xml") {
|
|
194
194
|
assignXmlContent(content, extracted);
|
|
@@ -15,6 +15,7 @@ import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.j
|
|
|
15
15
|
import { resolveThemeFont } from "../../utils/fontResolver.js";
|
|
16
16
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
17
17
|
import { decodeOoxmlSymbolCharacter } from "../../utils/ooxmlSymbol.js";
|
|
18
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
18
19
|
import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
|
|
19
20
|
import { getColumns } from "../sectionColumns.js";
|
|
20
21
|
import { groupParagraphFrames } from "./paragraphFrames.js";
|
|
@@ -454,12 +455,6 @@ function buildImageRun(attrs, constrained, pmStart, pmEnd, trackedChange) {
|
|
|
454
455
|
return run;
|
|
455
456
|
}
|
|
456
457
|
/**
|
|
457
|
-
* Paragraph styleId pattern used by Word for TOC entries (TOC, TOC1, TOC2, …).
|
|
458
|
-
* Hyperlinks inside these paragraphs must render in the paragraph's own colour,
|
|
459
|
-
* not the Hyperlink character style — see {@link stripTocHyperlinkStyle}.
|
|
460
|
-
*/
|
|
461
|
-
const TOC_STYLE_ID = /^TOC\d*$/iu;
|
|
462
|
-
/**
|
|
463
458
|
* In TOC paragraphs, strip the resolved Hyperlink character-style colour and
|
|
464
459
|
* underline so the painter's link fallback doesn't fire. The PM doc keeps the
|
|
465
460
|
* original marks so copy/paste out of a TOC still carries the Hyperlink
|
|
@@ -484,7 +479,7 @@ function paragraphToRuns(node, startPos, _options) {
|
|
|
484
479
|
const pmAttrs = expectParagraphAttrs(node);
|
|
485
480
|
const paraDefaults = paragraphRunDefaults(pmAttrs, theme);
|
|
486
481
|
const paragraphStyleId = pmAttrs.styleId;
|
|
487
|
-
const inTocParagraph =
|
|
482
|
+
const inTocParagraph = pmAttrs._tableOfContentsLevel !== void 0 || tableOfContentsStyleLevel({ styleId: paragraphStyleId }) !== void 0;
|
|
488
483
|
let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
|
|
489
484
|
function pushRunsForChild(child, childPos) {
|
|
490
485
|
if (child.type.name === "renderedPageBreak") {
|
|
@@ -2,7 +2,7 @@ import { EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_V
|
|
|
2
2
|
import { isParagraphDirection } from "../paragraphDirection.js";
|
|
3
3
|
import { TRACKED_CHANGE_PROVENANCE_VALUES } from "../schema/marks.js";
|
|
4
4
|
import { panic } from "better-result";
|
|
5
|
-
import { isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
5
|
+
import { DRAWING_RAW_XML_MODES, isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
6
6
|
//#region src/prosemirror/attrs/index.ts
|
|
7
7
|
const SECTION_BREAK_TYPES = [
|
|
8
8
|
"nextPage",
|
|
@@ -143,6 +143,7 @@ const readParagraphAttrs = (node) => {
|
|
|
143
143
|
optionalString(attrs, "textId", "paragraph.attrs.textId", issues);
|
|
144
144
|
optionalOneOf(attrs, "alignment", "paragraph.attrs.alignment", issues, PARAGRAPH_ALIGNMENT_VALUES);
|
|
145
145
|
optionalString(attrs, "styleId", "paragraph.attrs.styleId", issues);
|
|
146
|
+
optionalNumber(attrs, "_tableOfContentsLevel", "paragraph.attrs._tableOfContentsLevel", issues);
|
|
146
147
|
optionalBoolean(attrs, "kinsoku", "paragraph.attrs.kinsoku", issues);
|
|
147
148
|
optionalBoolean(attrs, "overflowPunctuation", "paragraph.attrs.overflowPunctuation", issues);
|
|
148
149
|
optionalBoolean(attrs, "suppressAutoHyphens", "paragraph.attrs.suppressAutoHyphens", issues);
|
|
@@ -357,6 +358,12 @@ const readImageAttrs = (node) => {
|
|
|
357
358
|
optionalString(attrs, "hlinkHref", "image.attrs.hlinkHref", issues);
|
|
358
359
|
optionalString(attrs, "hlinkRId", "image.attrs.hlinkRId", issues);
|
|
359
360
|
optionalString(attrs, "_docxRawXml", "image.attrs._docxRawXml", issues);
|
|
361
|
+
optionalOneOf(attrs, "_docxRawXmlMode", "image.attrs._docxRawXmlMode", issues, Object.values(DRAWING_RAW_XML_MODES));
|
|
362
|
+
const rawXml = attrs["_docxRawXml"];
|
|
363
|
+
if (attrs["_docxRawXmlMode"] === DRAWING_RAW_XML_MODES.PRESERVE_ONLY && (typeof rawXml !== "string" || rawXml.trim().length === 0)) issues.push({
|
|
364
|
+
path: "image.attrs._docxRawXml",
|
|
365
|
+
message: "Preservation-only drawings require raw XML."
|
|
366
|
+
});
|
|
360
367
|
optionalBoolean(attrs, "_docxObjectPreview", "image.attrs._docxObjectPreview", issues);
|
|
361
368
|
return attrsResult(attrs, issues);
|
|
362
369
|
};
|
|
@@ -422,6 +429,7 @@ const readShapeAttrs = (node) => {
|
|
|
422
429
|
const issues = [];
|
|
423
430
|
expectNodeType(node, "shape", issues);
|
|
424
431
|
optionalString(attrs, "shapeType", "shape.attrs.shapeType", issues);
|
|
432
|
+
optionalString(attrs, "geometryAdjustments", "shape.attrs.geometryAdjustments", issues);
|
|
425
433
|
optionalString(attrs, "shapeId", "shape.attrs.shapeId", issues);
|
|
426
434
|
optionalNumber(attrs, "width", "shape.attrs.width", issues);
|
|
427
435
|
optionalNumber(attrs, "height", "shape.attrs.height", issues);
|
|
@@ -105,7 +105,8 @@ const constrainImageSize = (width, height) => {
|
|
|
105
105
|
};
|
|
106
106
|
const imageNodeAt = (view, pos) => {
|
|
107
107
|
const node = view.state.doc.nodeAt(pos);
|
|
108
|
-
|
|
108
|
+
if (!node || node.type.name !== "image") return null;
|
|
109
|
+
return expectImageAttrs(node)._docxRawXmlMode ? null : node;
|
|
109
110
|
};
|
|
110
111
|
/** Change the wrap mode of the image at `pos`. Returns whether it applied. */
|
|
111
112
|
const applyImageWrapType = (view, pos, wrapType) => {
|
|
@@ -7,13 +7,27 @@ import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBa
|
|
|
7
7
|
import { applyRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
|
|
8
8
|
import { directionToBidi } from "../paragraphDirection.js";
|
|
9
9
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
10
|
+
import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
|
|
10
11
|
import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
|
|
11
12
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
12
13
|
import { runShadingAttrsToShading } from "./runShadingMark.js";
|
|
13
14
|
import { decodeSdtListItems, sdtPropertiesFromAttrs, sdtPropertiesMatchAttrs } from "./sdtAttrs.js";
|
|
14
15
|
import { textFormattingToMarks } from "./toProseDoc.js";
|
|
16
|
+
import { panic } from "better-result";
|
|
17
|
+
import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
15
18
|
import { Fragment } from "prosemirror-model";
|
|
16
19
|
//#region src/prosemirror/conversion/fromProseDoc.ts
|
|
20
|
+
/**
|
|
21
|
+
* ProseMirror to Document Conversion
|
|
22
|
+
*
|
|
23
|
+
* Converts a ProseMirror document back to our Document type.
|
|
24
|
+
* This enables round-trip editing: DOCX -> Document -> PM -> Document -> DOCX
|
|
25
|
+
*
|
|
26
|
+
* Key responsibilities:
|
|
27
|
+
* - Coalesce consecutive text with same marks into single Runs
|
|
28
|
+
* - Preserve paragraph attributes (paraId, textId, formatting)
|
|
29
|
+
* - Handle marks -> TextFormatting conversion
|
|
30
|
+
*/
|
|
17
31
|
function normalizeShapeOutlineStyle(style) {
|
|
18
32
|
if (!style) return;
|
|
19
33
|
if (style in OUTLINE_STYLE_CSS_ALIASES) return OUTLINE_STYLE_CSS_ALIASES[style];
|
|
@@ -1256,14 +1270,18 @@ function createImageRun(node) {
|
|
|
1256
1270
|
if (cropLeft !== void 0) crop.left = cropLeft;
|
|
1257
1271
|
image.crop = crop;
|
|
1258
1272
|
}
|
|
1259
|
-
const drawingContent = {
|
|
1260
|
-
type: "drawing",
|
|
1261
|
-
image
|
|
1262
|
-
};
|
|
1263
|
-
if (attrs._docxRawXml) drawingContent.rawXml = attrs._docxRawXml;
|
|
1264
1273
|
return {
|
|
1265
1274
|
type: "run",
|
|
1266
|
-
content: [
|
|
1275
|
+
content: [attrs._docxRawXmlMode === DRAWING_RAW_XML_MODES.PRESERVE_ONLY ? {
|
|
1276
|
+
type: "drawing",
|
|
1277
|
+
image,
|
|
1278
|
+
rawXml: attrs._docxRawXml ?? panic("Preservation-only ProseMirror image attrs must include raw XML."),
|
|
1279
|
+
rawXmlMode: DRAWING_RAW_XML_MODES.PRESERVE_ONLY
|
|
1280
|
+
} : {
|
|
1281
|
+
type: "drawing",
|
|
1282
|
+
image,
|
|
1283
|
+
...attrs._docxRawXml ? { rawXml: attrs._docxRawXml } : {}
|
|
1284
|
+
}]
|
|
1267
1285
|
};
|
|
1268
1286
|
}
|
|
1269
1287
|
/**
|
|
@@ -1280,6 +1298,8 @@ function createShapeRun(node) {
|
|
|
1280
1298
|
}
|
|
1281
1299
|
};
|
|
1282
1300
|
if (attrs.shapeId) shape.id = attrs.shapeId;
|
|
1301
|
+
const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments);
|
|
1302
|
+
if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
|
|
1283
1303
|
const shapeTransform = parseTransformAttr(attrs.transform);
|
|
1284
1304
|
if (shapeTransform) shape.transform = shapeTransform;
|
|
1285
1305
|
const wrap = { type: attrs.wrapType || "inline" };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
|
|
2
2
|
import { createStyleEngine } from "../../style-engine/styleEngine.js";
|
|
3
3
|
import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
|
|
4
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
4
5
|
import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
|
|
5
6
|
import { emuToPixels } from "../../utils/units.js";
|
|
6
7
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
@@ -13,8 +14,6 @@ import { marksToTextFormatting } from "./fromProseDoc.js";
|
|
|
13
14
|
import { shadingToRunShadingAttrs } from "./runShadingMark.js";
|
|
14
15
|
import { sdtAttrsFromProperties } from "./sdtAttrs.js";
|
|
15
16
|
//#region src/prosemirror/conversion/toProseDoc.ts
|
|
16
|
-
const TOC_STYLE_ID = /^TOC\d*$/iu;
|
|
17
|
-
const isTocStyleId = (styleId) => styleId !== void 0 && TOC_STYLE_ID.test(styleId);
|
|
18
17
|
/**
|
|
19
18
|
* Build a `nextTextBoxGroupId()` generator salted with a random per-load
|
|
20
19
|
* nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
|
|
@@ -128,7 +127,7 @@ function convertBlockSdt(blockSdt, convertBlocks) {
|
|
|
128
127
|
*/
|
|
129
128
|
function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
130
129
|
const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
|
|
131
|
-
const isTocParagraph =
|
|
130
|
+
const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
|
|
132
131
|
const inlineNodes = [];
|
|
133
132
|
let inlineOffset = 0;
|
|
134
133
|
let bookmarksArr;
|
|
@@ -280,10 +279,16 @@ function canCarryTrackedRunMark(node, markType) {
|
|
|
280
279
|
function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay) {
|
|
281
280
|
const formatting = paragraph.formatting;
|
|
282
281
|
const styleId = formatting?.styleId;
|
|
282
|
+
const styleName = styleId ? styleResolver?.getStyle(styleId)?.name : void 0;
|
|
283
|
+
const tableOfContentsLevel = tableOfContentsStyleLevel({
|
|
284
|
+
styleId,
|
|
285
|
+
...styleName ? { styleName } : {}
|
|
286
|
+
});
|
|
283
287
|
const attrs = {};
|
|
284
288
|
if (paragraph.paraId) attrs.paraId = paragraph.paraId;
|
|
285
289
|
if (paragraph.textId) attrs.textId = paragraph.textId;
|
|
286
290
|
if (styleId) attrs.styleId = styleId;
|
|
291
|
+
if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
|
|
287
292
|
if (formatting?.numPr) attrs.numPr = formatting.numPr;
|
|
288
293
|
if (formatting?.numPrFromStyle) attrs.numPrFromStyle = formatting.numPrFromStyle;
|
|
289
294
|
if (paragraph.listRendering?.numFmt) attrs.listNumFmt = paragraph.listRendering.numFmt;
|
|
@@ -350,7 +355,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
350
355
|
set("runInWithNext", formatting?.runInWithNext ?? stylePpr?.runInWithNext);
|
|
351
356
|
set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
|
|
352
357
|
set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
|
|
353
|
-
set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties:
|
|
358
|
+
set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 }));
|
|
354
359
|
if (!formatting?.numPr && stylePpr?.numPr && stylePpr.numPr.numId !== 0) {
|
|
355
360
|
attrs.numPr = stylePpr.numPr;
|
|
356
361
|
attrs.numPrFromStyle = stylePpr.numPr;
|
|
@@ -1050,7 +1055,11 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
|
|
|
1050
1055
|
return [];
|
|
1051
1056
|
case "renderedPageBreak": return [schema.node("renderedPageBreak").mark(marks)];
|
|
1052
1057
|
case "tab": return [schema.node("tab", content.positional ? { positional: content.positional } : void 0).mark(marks)];
|
|
1053
|
-
case "drawing": return [withHyperlinkBoundaryMarks(convertImage(
|
|
1058
|
+
case "drawing": return [withHyperlinkBoundaryMarks(convertImage({
|
|
1059
|
+
image: content.image,
|
|
1060
|
+
rawXml: content.rawXml,
|
|
1061
|
+
rawXmlMode: content.rawXmlMode
|
|
1062
|
+
}), marks)];
|
|
1054
1063
|
case "shape": {
|
|
1055
1064
|
const shp = content.shape;
|
|
1056
1065
|
if (shp.textBody) {
|
|
@@ -1089,7 +1098,7 @@ function withHyperlinkBoundaryMarks(node, marks) {
|
|
|
1089
1098
|
if (!marks.some((mark) => mark.type.name === "hyperlink")) return node;
|
|
1090
1099
|
return node.mark(marks);
|
|
1091
1100
|
}
|
|
1092
|
-
function convertImage(image, rawXml) {
|
|
1101
|
+
function convertImage({ image, rawXml, rawXmlMode }) {
|
|
1093
1102
|
const imageSize = image.size;
|
|
1094
1103
|
const widthPx = imageSize?.width ? emuToPixels(imageSize.width) : void 0;
|
|
1095
1104
|
const heightPx = imageSize?.height ? emuToPixels(imageSize.height) : void 0;
|
|
@@ -1190,6 +1199,7 @@ function convertImage(image, rawXml) {
|
|
|
1190
1199
|
hlinkHref: image.hlinkHref,
|
|
1191
1200
|
hlinkRId: image.hlinkRId,
|
|
1192
1201
|
_docxRawXml: rawXml,
|
|
1202
|
+
_docxRawXmlMode: rawXmlMode,
|
|
1193
1203
|
_docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
|
|
1194
1204
|
});
|
|
1195
1205
|
}
|
|
@@ -1347,6 +1357,7 @@ function convertShape(shape) {
|
|
|
1347
1357
|
};
|
|
1348
1358
|
return schema.node("shape", {
|
|
1349
1359
|
shapeType: shapeAttrs.shapeType ?? "rect",
|
|
1360
|
+
geometryAdjustments: shape.geometryAdjustments === void 0 ? void 0 : JSON.stringify(shape.geometryAdjustments),
|
|
1350
1361
|
shapeId: shape.id,
|
|
1351
1362
|
width: widthPx,
|
|
1352
1363
|
height: heightPx,
|
|
@@ -6,6 +6,8 @@ import { EditorState } from "prosemirror-state";
|
|
|
6
6
|
type ResolvedStyleAttrs = {
|
|
7
7
|
paragraphFormatting?: document_d_exports.ParagraphFormatting;
|
|
8
8
|
runFormatting?: document_d_exports.TextFormatting;
|
|
9
|
+
/** Canonical OOXML style name, used when the document-local style id is localized. */
|
|
10
|
+
styleName?: string;
|
|
9
11
|
/**
|
|
10
12
|
* Numbering definitions from the document package. When the applied style
|
|
11
13
|
* carries a `w:numPr`, these resolve the numbering level into the list
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { paragraphToStyle } from "../../../utils/formatToStyle.js";
|
|
2
2
|
import { collectHeadings } from "../../../utils/headingCollector.js";
|
|
3
|
+
import { tableOfContentsStyleLevel } from "../../../utils/tableOfContentsStyle.js";
|
|
3
4
|
import { expectParagraphAttrs } from "../../attrs/index.js";
|
|
4
5
|
import { autospacingMatchesBase } from "../../autospacingBase.js";
|
|
5
6
|
import { directionIsRtl } from "../../paragraphDirection.js";
|
|
@@ -215,6 +216,7 @@ const paragraphNodeSpec = {
|
|
|
215
216
|
listAbstractNumId: { default: null },
|
|
216
217
|
listStartOverride: { default: null },
|
|
217
218
|
styleId: { default: null },
|
|
219
|
+
_tableOfContentsLevel: { default: null },
|
|
218
220
|
borders: { default: null },
|
|
219
221
|
shading: { default: null },
|
|
220
222
|
tabs: { default: null },
|
|
@@ -248,11 +250,13 @@ const paragraphNodeSpec = {
|
|
|
248
250
|
const paraId = element.dataset["paraId"];
|
|
249
251
|
const alignment = element.dataset["alignment"];
|
|
250
252
|
const styleId = element.dataset["styleId"];
|
|
253
|
+
const tableOfContentsLevel = Number(element.dataset["tableOfContentsLevel"]);
|
|
251
254
|
const sectionBreakType = element.dataset["sectionBreak"];
|
|
252
255
|
const attrs = {
|
|
253
256
|
...paraId ? { paraId } : {},
|
|
254
257
|
...alignment ? { alignment } : {},
|
|
255
258
|
...styleId ? { styleId } : {},
|
|
259
|
+
...Number.isSafeInteger(tableOfContentsLevel) && tableOfContentsLevel > 0 ? { _tableOfContentsLevel: tableOfContentsLevel } : {},
|
|
256
260
|
...sectionBreakType ? { sectionBreakType } : {}
|
|
257
261
|
};
|
|
258
262
|
const styleAttrs = extractParagraphAttrsFromStyle(element);
|
|
@@ -291,6 +295,7 @@ const paragraphNodeSpec = {
|
|
|
291
295
|
if (attrs.paraId) domAttrs["data-para-id"] = attrs.paraId;
|
|
292
296
|
if (attrs.alignment) domAttrs["data-alignment"] = attrs.alignment;
|
|
293
297
|
if (attrs.styleId) domAttrs["data-style-id"] = attrs.styleId;
|
|
298
|
+
if (typeof attrs._tableOfContentsLevel === "number") domAttrs["data-table-of-contents-level"] = String(attrs._tableOfContentsLevel);
|
|
294
299
|
if (attrs.listMarker) domAttrs["data-list-marker"] = attrs.listMarker;
|
|
295
300
|
if (directionIsRtl(attrs.direction)) domAttrs["dir"] = "rtl";
|
|
296
301
|
if (attrs.sectionBreakType) {
|
|
@@ -460,10 +465,14 @@ function makeApplyStyle(schema) {
|
|
|
460
465
|
seen.add(pos);
|
|
461
466
|
const newAttrs = {
|
|
462
467
|
...node.attrs,
|
|
463
|
-
styleId
|
|
468
|
+
styleId,
|
|
469
|
+
_tableOfContentsLevel: tableOfContentsStyleLevel({ styleId }) ?? null
|
|
464
470
|
};
|
|
465
471
|
if (resolvedAttrs) {
|
|
466
|
-
Object.assign(newAttrs, paragraphAttrsFromResolvedStyle(resolvedAttrs
|
|
472
|
+
Object.assign(newAttrs, paragraphAttrsFromResolvedStyle(resolvedAttrs, {
|
|
473
|
+
styleId,
|
|
474
|
+
...resolvedAttrs.styleName ? { styleName: resolvedAttrs.styleName } : {}
|
|
475
|
+
}));
|
|
467
476
|
const listAttrs = listAttrsFromResolvedStyle(resolvedAttrs, resolvedAttrs.numbering);
|
|
468
477
|
if (listAttrs) Object.assign(newAttrs, listAttrs);
|
|
469
478
|
}
|
|
@@ -534,7 +543,10 @@ const ParagraphExtension = createNodeExtension({
|
|
|
534
543
|
hangingIndent: hanging ?? false
|
|
535
544
|
}),
|
|
536
545
|
applyStyle: (styleId, resolvedAttrs) => applyStyleFn(styleId, resolvedAttrs),
|
|
537
|
-
clearStyle: () =>
|
|
546
|
+
clearStyle: () => setParagraphAttrsCmd({
|
|
547
|
+
styleId: null,
|
|
548
|
+
_tableOfContentsLevel: null
|
|
549
|
+
}),
|
|
538
550
|
insertSectionBreak: (breakType) => setParagraphAttr("sectionBreakType", breakType),
|
|
539
551
|
removeSectionBreak: () => setParagraphAttr("sectionBreakType", null),
|
|
540
552
|
generateTOC: () => (state, dispatch) => {
|
|
@@ -53,6 +53,7 @@ const clearIndentOnBackspace = (state, dispatch) => {
|
|
|
53
53
|
const INHERITED_PARA_ATTRS = [
|
|
54
54
|
"defaultTextFormatting",
|
|
55
55
|
"styleId",
|
|
56
|
+
"_tableOfContentsLevel",
|
|
56
57
|
"lineSpacing",
|
|
57
58
|
"lineSpacingRule",
|
|
58
59
|
"snapToGrid",
|
|
@@ -77,11 +78,15 @@ function applyNextParagraphStyle(tr, sourcePara, newPara, resolver) {
|
|
|
77
78
|
const nextStyleId = resolver.getNextStyleId(sourcePara.attrs["styleId"]);
|
|
78
79
|
if (!nextStyleId) return false;
|
|
79
80
|
const resolved = resolver.resolveParagraphStyle(nextStyleId);
|
|
81
|
+
const styleName = resolver.getStyle(nextStyleId)?.name;
|
|
80
82
|
const { $from } = tr.selection;
|
|
81
83
|
tr.setNodeMarkup($from.before(), void 0, {
|
|
82
84
|
...newPara.attrs,
|
|
83
85
|
styleId: nextStyleId,
|
|
84
|
-
...paragraphAttrsFromResolvedStyle(resolved
|
|
86
|
+
...paragraphAttrsFromResolvedStyle(resolved, {
|
|
87
|
+
styleId: nextStyleId,
|
|
88
|
+
...styleName ? { styleName } : {}
|
|
89
|
+
})
|
|
85
90
|
});
|
|
86
91
|
tr.setStoredMarks(resolved.runFormatting ? textFormattingToMarks(resolved.runFormatting, tr.doc.type.schema) : []);
|
|
87
92
|
return true;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { document_d_exports } from "../../../types/document.js";
|
|
1
2
|
import { ShapeAttrs as ShapeAttrs$1 } from "../../schema/nodes.js";
|
|
2
3
|
import { NodeExtension } from "../types.js";
|
|
3
4
|
//#region src/prosemirror/extensions/nodes/ShapeExtension.d.ts
|
|
@@ -7,6 +8,11 @@ declare function sanitizeTransform(value: string | null | undefined): string | n
|
|
|
7
8
|
declare function sanitizeSvgId(value: string | null | undefined): string | null;
|
|
8
9
|
declare function sanitizeShapeDimension(value: number | null | undefined, fallback: number): number;
|
|
9
10
|
declare function strokeDashArrayForOutlineStyle(outlineStyle: string | undefined): string | undefined;
|
|
11
|
+
type RightBracePaths = {
|
|
12
|
+
fill: string;
|
|
13
|
+
outline: string;
|
|
14
|
+
};
|
|
15
|
+
declare function buildRightBracePaths(w: number, h: number, adjustments: readonly document_d_exports.ShapeGeometryAdjustment[]): RightBracePaths;
|
|
10
16
|
/**
|
|
11
17
|
* Build the `points` string for a polygon-based shape preset.
|
|
12
18
|
*
|
|
@@ -26,4 +32,4 @@ type GradientStop = {
|
|
|
26
32
|
declare function parseGradientStops(raw: string | undefined): GradientStop[];
|
|
27
33
|
declare const ShapeExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
|
|
28
34
|
//#endregion
|
|
29
|
-
export { ShapeAttrs, ShapeExtension, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
35
|
+
export { ShapeAttrs, ShapeExtension, buildRightBracePaths, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { expectShapeAttrs } from "../../attrs/index.js";
|
|
2
|
+
import { parseShapeGeometryAdjustments } from "../../shapeGeometryAdjustments.js";
|
|
2
3
|
import { createNodeExtension } from "../create.js";
|
|
3
4
|
//#region src/prosemirror/extensions/nodes/ShapeExtension.ts
|
|
4
5
|
/**
|
|
@@ -123,6 +124,40 @@ function setNum(el, name, value) {
|
|
|
123
124
|
function fmt(n) {
|
|
124
125
|
return Number.isInteger(n) ? String(n) : Number(n.toFixed(3)).toString();
|
|
125
126
|
}
|
|
127
|
+
const RIGHT_BRACE_DEFAULT_THICKNESS = 8333;
|
|
128
|
+
const RIGHT_BRACE_DEFAULT_CUSP = 5e4;
|
|
129
|
+
const GEOMETRY_PERCENT_SCALE = 1e5;
|
|
130
|
+
const geometryAdjustment = (adjustments, name, fallback) => {
|
|
131
|
+
const authored = adjustments.find((adjustment) => adjustment.name === name);
|
|
132
|
+
if (!authored) return fallback;
|
|
133
|
+
const match = /^val\s+(-?\d+)$/u.exec(authored.formula);
|
|
134
|
+
if (!match) return fallback;
|
|
135
|
+
return Number(match.at(1));
|
|
136
|
+
};
|
|
137
|
+
function buildRightBracePaths(w, h, adjustments) {
|
|
138
|
+
const shortSide = Math.min(w, h);
|
|
139
|
+
const cuspAdjustment = Math.min(GEOMETRY_PERCENT_SCALE, Math.max(0, geometryAdjustment(adjustments, "adj2", RIGHT_BRACE_DEFAULT_CUSP)));
|
|
140
|
+
const maxThickness = Math.min(cuspAdjustment, GEOMETRY_PERCENT_SCALE - cuspAdjustment) / 2 * h / shortSide;
|
|
141
|
+
const radius = shortSide * Math.min(maxThickness, Math.max(0, geometryAdjustment(adjustments, "adj1", RIGHT_BRACE_DEFAULT_THICKNESS))) / GEOMETRY_PERCENT_SCALE;
|
|
142
|
+
const halfWidth = w / 2;
|
|
143
|
+
const cusp = h * cuspAdjustment / GEOMETRY_PERCENT_SCALE;
|
|
144
|
+
const upperStemEnd = cusp - radius;
|
|
145
|
+
const lowerStemStart = cusp + radius;
|
|
146
|
+
const bottomCurveStart = h - radius;
|
|
147
|
+
const commands = [
|
|
148
|
+
"M 0 0",
|
|
149
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 1 ${fmt(halfWidth)} ${fmt(radius)}`,
|
|
150
|
+
`L ${fmt(halfWidth)} ${fmt(upperStemEnd)}`,
|
|
151
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 0 ${fmt(w)} ${fmt(cusp)}`,
|
|
152
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 0 ${fmt(halfWidth)} ${fmt(lowerStemStart)}`,
|
|
153
|
+
`L ${fmt(halfWidth)} ${fmt(bottomCurveStart)}`,
|
|
154
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 1 0 ${fmt(h)}`
|
|
155
|
+
].join(" ");
|
|
156
|
+
return {
|
|
157
|
+
fill: `${commands} Z`,
|
|
158
|
+
outline: commands
|
|
159
|
+
};
|
|
160
|
+
}
|
|
126
161
|
/**
|
|
127
162
|
* Build the `points` string for a polygon-based shape preset.
|
|
128
163
|
*
|
|
@@ -209,7 +244,7 @@ function buildShapePolygonPoints(type, w, h) {
|
|
|
209
244
|
* displays. The original `<a:prstGeom prst>` value round-trips through the
|
|
210
245
|
* model regardless of what the renderer chooses to draw.
|
|
211
246
|
*/
|
|
212
|
-
function createShapeElement(type, w, h) {
|
|
247
|
+
function createShapeElement(type, w, h, adjustments) {
|
|
213
248
|
switch (type) {
|
|
214
249
|
case "ellipse":
|
|
215
250
|
case "oval": {
|
|
@@ -238,6 +273,19 @@ function createShapeElement(type, w, h) {
|
|
|
238
273
|
setNum(el, "y2", h / 2);
|
|
239
274
|
return el;
|
|
240
275
|
}
|
|
276
|
+
case "rightBrace": {
|
|
277
|
+
const paths = buildRightBracePaths(w, h, adjustments);
|
|
278
|
+
const group = document.createElementNS(SVG_NS, "g");
|
|
279
|
+
const fill = document.createElementNS(SVG_NS, "path");
|
|
280
|
+
fill.setAttribute("d", paths.fill);
|
|
281
|
+
fill.setAttribute("stroke", "none");
|
|
282
|
+
group.append(fill);
|
|
283
|
+
const outline = document.createElementNS(SVG_NS, "path");
|
|
284
|
+
outline.setAttribute("d", paths.outline);
|
|
285
|
+
outline.setAttribute("fill", "none");
|
|
286
|
+
group.append(outline);
|
|
287
|
+
return group;
|
|
288
|
+
}
|
|
241
289
|
default: {
|
|
242
290
|
const points = buildShapePolygonPoints(type, w, h);
|
|
243
291
|
if (points !== null) {
|
|
@@ -320,6 +368,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
320
368
|
atom: true,
|
|
321
369
|
attrs: {
|
|
322
370
|
shapeType: { default: "rect" },
|
|
371
|
+
geometryAdjustments: { default: null },
|
|
323
372
|
shapeId: { default: null },
|
|
324
373
|
width: { default: 100 },
|
|
325
374
|
height: { default: 80 },
|
|
@@ -362,6 +411,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
362
411
|
const outlineTailEnd = parseShapeLineEnd(d["outlineTailEnd"]);
|
|
363
412
|
return {
|
|
364
413
|
shapeType: d["shapeType"] || "rect",
|
|
414
|
+
...d["geometryAdjustments"] ? { geometryAdjustments: d["geometryAdjustments"] } : {},
|
|
365
415
|
...d["shapeId"] ? { shapeId: d["shapeId"] } : {},
|
|
366
416
|
...d["width"] ? { width: Number(d["width"]) } : {},
|
|
367
417
|
...d["height"] ? { height: Number(d["height"]) } : {},
|
|
@@ -403,6 +453,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
403
453
|
class: "docx-shape",
|
|
404
454
|
"data-shape-type": attrs.shapeType || "rect"
|
|
405
455
|
};
|
|
456
|
+
if (attrs.geometryAdjustments) domAttrs["data-geometry-adjustments"] = attrs.geometryAdjustments;
|
|
406
457
|
if (attrs.shapeId) domAttrs["data-shape-id"] = attrs.shapeId;
|
|
407
458
|
domAttrs["data-width"] = String(w);
|
|
408
459
|
domAttrs["data-height"] = String(h);
|
|
@@ -489,7 +540,8 @@ const ShapeExtension = createNodeExtension({
|
|
|
489
540
|
defs.append(gradient);
|
|
490
541
|
svg.append(defs);
|
|
491
542
|
}
|
|
492
|
-
const
|
|
543
|
+
const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments) ?? [];
|
|
544
|
+
const shapeEl = createShapeElement(attrs.shapeType || "rect", w, h, geometryAdjustments);
|
|
493
545
|
const strokeDasharray = strokeDashArrayForOutlineStyle(attrs.outlineStyle);
|
|
494
546
|
if (strokeDasharray) shapeEl.setAttribute("stroke-dasharray", strokeDasharray);
|
|
495
547
|
svg.append(shapeEl);
|
|
@@ -501,4 +553,4 @@ const ShapeExtension = createNodeExtension({
|
|
|
501
553
|
}
|
|
502
554
|
});
|
|
503
555
|
//#endregion
|
|
504
|
-
export { ShapeExtension, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
556
|
+
export { ShapeExtension, buildRightBracePaths, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
@@ -102,6 +102,8 @@ type ParagraphAttrs = {
|
|
|
102
102
|
/** Numbering start override for this numId/level. */
|
|
103
103
|
listStartOverride?: number;
|
|
104
104
|
styleId?: string;
|
|
105
|
+
/** Imported built-in TOC entry level, resolved from the canonical style name. */
|
|
106
|
+
_tableOfContentsLevel?: number;
|
|
105
107
|
borders?: {
|
|
106
108
|
top?: document_d_exports.BorderSpec;
|
|
107
109
|
bottom?: document_d_exports.BorderSpec;
|
|
@@ -275,6 +277,8 @@ type ImageAttrs = {
|
|
|
275
277
|
hlinkRId?: string;
|
|
276
278
|
/** Original OOXML for opaque/unsupported DOCX drawings. */
|
|
277
279
|
_docxRawXml?: string;
|
|
280
|
+
/** Raw XML preserved without an editable image projection. */
|
|
281
|
+
_docxRawXmlMode?: document_d_exports.DrawingRawXmlMode;
|
|
278
282
|
/** Embedded-object previews use their authored box as the exact line height. */
|
|
279
283
|
_docxObjectPreview?: boolean;
|
|
280
284
|
};
|
|
@@ -382,6 +386,8 @@ type BlockSdtAttrs = {
|
|
|
382
386
|
type ShapeAttrs = {
|
|
383
387
|
/** Shape type preset */
|
|
384
388
|
shapeType?: string;
|
|
389
|
+
/** Preset geometry adjustments serialized as JSON. */
|
|
390
|
+
geometryAdjustments?: string;
|
|
385
391
|
/** Unique identifier */
|
|
386
392
|
shapeId?: string;
|
|
387
393
|
/** Width in pixels */
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/prosemirror/shapeGeometryAdjustments.d.ts
|
|
3
|
+
declare const parseShapeGeometryAdjustments: (raw: string | undefined) => document_d_exports.ShapeGeometryAdjustment[] | undefined;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { parseShapeGeometryAdjustments };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/prosemirror/shapeGeometryAdjustments.ts
|
|
2
|
+
const MAX_ADJUSTMENT_COUNT = 32;
|
|
3
|
+
const MAX_ADJUSTMENT_NAME_LENGTH = 64;
|
|
4
|
+
const MAX_ADJUSTMENT_FORMULA_LENGTH = 128;
|
|
5
|
+
const parseShapeGeometryAdjustments = (raw) => {
|
|
6
|
+
if (!raw) return;
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (!Array.isArray(parsed) || parsed.length > MAX_ADJUSTMENT_COUNT) return;
|
|
10
|
+
const adjustments = [];
|
|
11
|
+
for (const item of parsed) {
|
|
12
|
+
if (typeof item !== "object" || item === null || !("name" in item) || typeof item.name !== "string" || item.name.length === 0 || item.name.length > MAX_ADJUSTMENT_NAME_LENGTH || !("formula" in item) || typeof item.formula !== "string" || item.formula.length === 0 || item.formula.length > MAX_ADJUSTMENT_FORMULA_LENGTH) return;
|
|
13
|
+
adjustments.push({
|
|
14
|
+
name: item.name,
|
|
15
|
+
formula: item.formula
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return adjustments.length === 0 ? void 0 : adjustments;
|
|
19
|
+
} catch {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { parseShapeGeometryAdjustments };
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { NumberingMap } from "../../docx/numberingParser.js";
|
|
2
2
|
import { ResolvedParagraphStyle } from "./styleResolver.js";
|
|
3
3
|
//#region src/prosemirror/styles/resolvedStyleAttrs.d.ts
|
|
4
|
+
type ResolvedStyleIdentity = {
|
|
5
|
+
styleId: string;
|
|
6
|
+
styleName?: string;
|
|
7
|
+
};
|
|
4
8
|
/**
|
|
5
9
|
* The paragraph attrs a style definition controls. Applying a style resets
|
|
6
10
|
* every one of these to the style's value (or `null` to clear), so a prior
|
|
7
11
|
* style's properties (e.g. a heading's spacing) never leak through. Returns
|
|
8
12
|
* a partial attrs object to merge over the paragraph's existing attrs.
|
|
9
13
|
*/
|
|
10
|
-
declare function paragraphAttrsFromResolvedStyle(resolved: ResolvedParagraphStyle): Record<string, unknown>;
|
|
14
|
+
declare function paragraphAttrsFromResolvedStyle(resolved: ResolvedParagraphStyle, identity: ResolvedStyleIdentity): Record<string, unknown>;
|
|
11
15
|
/**
|
|
12
16
|
* The list attrs a style's `w:pPr/w:numPr` controls (numbering reference plus
|
|
13
17
|
* the baked marker-rendering attrs that `toProseDoc` normally derives from
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeListRendering } from "../../docx/numberingParser.js";
|
|
2
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
2
3
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
3
4
|
//#region src/prosemirror/styles/resolvedStyleAttrs.ts
|
|
4
5
|
/**
|
|
@@ -17,7 +18,7 @@ import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
|
17
18
|
* style's properties (e.g. a heading's spacing) never leak through. Returns
|
|
18
19
|
* a partial attrs object to merge over the paragraph's existing attrs.
|
|
19
20
|
*/
|
|
20
|
-
function paragraphAttrsFromResolvedStyle(resolved) {
|
|
21
|
+
function paragraphAttrsFromResolvedStyle(resolved, identity) {
|
|
21
22
|
const ppr = resolved.paragraphFormatting;
|
|
22
23
|
const runFormatting = resolved.runFormatting;
|
|
23
24
|
const hasRunFormatting = !!runFormatting && Object.keys(runFormatting).length > 0;
|
|
@@ -40,7 +41,8 @@ function paragraphAttrsFromResolvedStyle(resolved) {
|
|
|
40
41
|
outlineLevel: ppr?.outlineLevel ?? null,
|
|
41
42
|
borders: ppr?.borders ?? null,
|
|
42
43
|
defaultTextFormatting: hasRunFormatting ? runFormatting : null,
|
|
43
|
-
_autospacingBase: autospacingBaseFromResolvedParagraphFormatting(ppr)
|
|
44
|
+
_autospacingBase: autospacingBaseFromResolvedParagraphFormatting(ppr),
|
|
45
|
+
_tableOfContentsLevel: tableOfContentsStyleLevel(identity) ?? null
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
function autospacingBaseFromResolvedParagraphFormatting(ppr) {
|
package/dist/redline.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createFolioAITextRangeHandle } from "./ai-edits/snapshot.js";
|
|
|
3
3
|
import "./document-operations.js";
|
|
4
4
|
import { pairFolioDocumentStories } from "./document-stories.js";
|
|
5
5
|
import { resolveFolioDocumentPrivacyTransforms, rewriteDocxMetadataPrivacy } from "./docx/metadataPrivacy.js";
|
|
6
|
+
import { GenerateRedlineDocxOperationLimitError } from "./redlineOperationLimit.js";
|
|
6
7
|
import { alignFolioBlocks } from "./version-comparison.js";
|
|
7
8
|
import { TaggedError, panic } from "better-result";
|
|
8
9
|
//#region src/redline.ts
|
|
@@ -71,11 +72,14 @@ const formattingSegments = (baseBlock, revisedBlock) => {
|
|
|
71
72
|
if (hasInlineFormatting(formatting)) {
|
|
72
73
|
const previous = segments.at(-1);
|
|
73
74
|
if (previous && previous.endOffset === textOffset && sameInlineFormatting(previous.formatting, formatting)) previous.endOffset += length;
|
|
74
|
-
else
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
else {
|
|
76
|
+
if (segments.length >= 1e4) throw new GenerateRedlineDocxOperationLimitError({ message: "The document comparison exceeds the generated operation limit." });
|
|
77
|
+
segments.push({
|
|
78
|
+
startOffset: textOffset,
|
|
79
|
+
endOffset: textOffset + length,
|
|
80
|
+
formatting
|
|
81
|
+
});
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
textOffset += length;
|
|
81
85
|
baseRunOffset += length;
|
|
@@ -199,7 +203,10 @@ const generateRedlineDocx = async (base, revised, options = {}) => {
|
|
|
199
203
|
const skipped = [];
|
|
200
204
|
const unprocessedStories = [];
|
|
201
205
|
let operationSequence = 0;
|
|
202
|
-
const nextOperationId = () =>
|
|
206
|
+
const nextOperationId = () => {
|
|
207
|
+
if (operationSequence >= 1e4) throw new GenerateRedlineDocxOperationLimitError({ message: "The document comparison exceeds the generated operation limit." });
|
|
208
|
+
return `redline-${++operationSequence}`;
|
|
209
|
+
};
|
|
203
210
|
for (const pair of pairFolioDocumentStories(baseStories, revisedStories)) {
|
|
204
211
|
if (!pair.baseStory) {
|
|
205
212
|
unprocessedStories.push({
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/redlineOperationLimit.d.ts
|
|
2
|
+
declare const MAX_GENERATED_REDLINE_OPERATIONS = 10000;
|
|
3
|
+
declare const GenerateRedlineDocxOperationLimitError_base: import("better-result").TaggedErrorClass<"GenerateRedlineDocxOperationLimitError">;
|
|
4
|
+
declare class GenerateRedlineDocxOperationLimitError extends GenerateRedlineDocxOperationLimitError_base<{
|
|
5
|
+
message: string;
|
|
6
|
+
}> {}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { GenerateRedlineDocxOperationLimitError, MAX_GENERATED_REDLINE_OPERATIONS };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TaggedError } from "better-result";
|
|
2
|
+
//#region src/redlineOperationLimit.ts
|
|
3
|
+
const MAX_GENERATED_REDLINE_OPERATIONS = 1e4;
|
|
4
|
+
var GenerateRedlineDocxOperationLimitError = class extends TaggedError("GenerateRedlineDocxOperationLimitError") {};
|
|
5
|
+
//#endregion
|
|
6
|
+
export { GenerateRedlineDocxOperationLimitError, MAX_GENERATED_REDLINE_OPERATIONS };
|
package/dist/server.d.ts
CHANGED
|
@@ -20,10 +20,10 @@ import { FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLI
|
|
|
20
20
|
import { ApplyDocxXmlPatchProposalArgs, FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FolioDocxXmlPatchApplication, FolioDocxXmlPatchApplicationError, FolioDocxXmlPatchApplicationReceipt, UnsupportedFolioDocxXmlPatchApplicationProfileError, applyDocxXmlPatchProposal } from "./docx/server/applyDocxXmlPatchProposal.js";
|
|
21
21
|
import { HEADING_LEVELS, HeadingLevel, InvalidFolioReportBuilderOptionsError, TableCellSpec, bookmark, createTableOfContentsField, endnote, heading, hyperlink, pageBreak, paragraph, run, table } from "./docx/server/build.js";
|
|
22
22
|
import { BilingualBorders, BilingualParagraphRef, BilingualRow, BilingualRowKind, BilingualTableParagraphRef, CreateBilingualDocumentOptions, CreateBilingualDocumentResult, InvalidBilingualDocumentOptionsError, createBilingualDocument, readBilingualDocument } from "./docx/server/createBilingualDocument.js";
|
|
23
|
-
import { CreateBilingualDocxResult, createBilingualDocx, readBilingualDocx } from "./docx/server/createBilingualDocx.js";
|
|
23
|
+
import { CreateBilingualDocxOptions, CreateBilingualDocxResult, createBilingualDocx, readBilingualDocx } from "./docx/server/createBilingualDocx.js";
|
|
24
24
|
import { docxToMarkdown } from "./docx/server/docxToMarkdown.js";
|
|
25
25
|
import { DocxParagraphSource, DocxTableRowKind, DocxTableRowPosition, ExtractedDocxParagraph, ExtractedDocxTableCell, ExtractedDocxTableCellParagraph, ExtractedDocxText, extractDocxText } from "./docx/server/extractDocxText.js";
|
|
26
26
|
import { FOLIO_DOCX_PACKAGE_INSPECTION_DEFAULTS, FOLIO_DOCX_PACKAGE_INSPECTION_ERROR_CODES, FOLIO_DOCX_PACKAGE_INSPECTION_VERSION, FolioDocxInspectedXmlPart, FolioDocxPackageInspection, FolioDocxPackageInspectionError, FolioDocxPackageInspectionErrorCode, FolioDocxPackageInspectionLimits, FolioDocxPackagePart, FolioDocxPackagePartKind, InspectDocxPackageOptions, inspectDocxPackage } from "./docx/server/inspectDocxPackage.js";
|
|
27
27
|
import { GenerateRedlineDocxOptions, GenerateRedlineDocxResult, GenerateRedlineUnprocessedStory, InvalidGenerateRedlineDocxOptionsError, generateRedlineDocx } from "./redline.js";
|
|
28
28
|
import { FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, FolioBlockDiff, FolioCompareDocxVersionsOptions, FolioDocumentMetadataValue, FolioFormatProperty, FolioMetadataDiff, FolioStoryDiff, FolioVersionBlockHandle, FolioVersionComparisonPrivacyTransform, FolioVersionComparisonScope, FolioVersionDiff, FolioVersionDiffPrivacyOptions, FolioVersionDiffPrivacyReport, FolioVersionDiffSegment, FolioVersionDiffSummaryCounts, InvalidFolioVersionComparisonOptionsError, applyFolioVersionDiffPrivacy, compareDocxVersions, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope } from "./version-comparison.js";
|
|
29
|
-
export { type ApplyDocxXmlPatchProposalArgs, type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, type BilingualBorders, type BilingualParagraphRef, type BilingualRow, type BilingualRowKind, type BilingualTableParagraphRef, type CreateBilingualDocumentOptions, type CreateBilingualDocumentResult, type CreateBilingualDocxResult, type CreateCommentReplyInput, type CreateEmptyDocumentOptions, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, type DeriveBlockIdInput, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, DocxArchiveError, type DocxArchiveOptions, type DocxParagraphSource, type DocxTableRowKind, type DocxTableRowPosition, EnsureParaIdsError, type EnsureParaIdsOptions, type EnsureParaIdsResult, type EvaluateDocxXmlPatchProposalArgs, type ExtractDocumentStyleSetOptions, type ExtractedDocxParagraph, type ExtractedDocxTableCell, type ExtractedDocxTableCellParagraph, type ExtractedDocxText, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLIO_DOCX_CONFORMANCE_PROFILE, FOLIO_DOCX_CONFORMANCE_REPORT_VERSION, FOLIO_DOCX_PACKAGE_INSPECTION_DEFAULTS, FOLIO_DOCX_PACKAGE_INSPECTION_ERROR_CODES, FOLIO_DOCX_PACKAGE_INSPECTION_VERSION, FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FOLIO_DOCX_XML_PATCH_PROPOSAL_DEFAULTS, FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES, FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditSnapshot, type FolioAIInlineFormatting, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsOptions, type FolioApplyDocumentOperationsToStoryOptions, type FolioApplyOperationsOptions, type FolioBlockDiff, type FolioBlockId, type FolioCompareDocxVersionsOptions, type FolioDocumentMetadataProperty, type FolioDocumentMetadataValue, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, FolioDocumentPrivacyArchiveError, type FolioDocumentPrivacyOptions, type FolioDocumentPrivacyReport, type FolioDocumentPrivacyTransform, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioDocxConformanceCheck, type FolioDocxConformanceCheckId, type FolioDocxConformanceCheckStatus, type FolioDocxConformanceIssue, type FolioDocxConformanceIssueCode, type FolioDocxConformanceReport, type FolioDocxConformanceStatus, type FolioDocxInspectedXmlPart, type FolioDocxPackageInspection, FolioDocxPackageInspectionError, type FolioDocxPackageInspectionErrorCode, type FolioDocxPackageInspectionLimits, type FolioDocxPackagePart, type FolioDocxPackagePartKind, type FolioDocxPreparedXmlReplacement, FolioDocxReviewer, type FolioDocxReviewerOptions, type FolioDocxXmlPatchApplication, FolioDocxXmlPatchApplicationError, type FolioDocxXmlPatchApplicationReceipt, type FolioDocxXmlPatchProposal, type FolioDocxXmlPatchProposalEvaluation, type FolioDocxXmlPatchProposalIssue, type FolioDocxXmlPatchProposalIssueCode, type FolioDocxXmlPatchProposalLimits, type FolioDocxXmlReplacement, type FolioEditableDocumentStoryHandle, type FolioFormatProperty, type FolioMetadataDiff, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeFilter, type FolioReviewChangeKind, type FolioReviewComment, type FolioReviewCommentFilter, type FolioReviewCommentReply, type FolioReviewReplyInput, type FolioReviewedStory, type FolioReviewedView, type FolioStoryDiff, type FolioVersionBlockHandle, type FolioVersionComparisonPrivacyTransform, type FolioVersionComparisonScope, type FolioVersionDiff, type FolioVersionDiffPrivacyOptions, type FolioVersionDiffPrivacyReport, type FolioVersionDiffSegment, type FolioVersionDiffSummaryCounts, type GenerateRedlineDocxOptions, type GenerateRedlineDocxResult, type GenerateRedlineUnprocessedStory, HEADING_LEVELS, type HeadingLevel, type InspectDocxPackageOptions, InvalidBilingualDocumentOptionsError, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, InvalidFolioReportBuilderOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, type ParseOptions, type RewriteDocxMetadataPrivacyResult, STELLA_STYLE_SET_NAME, type TableCellSpec, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioDocxXmlPatchApplicationProfileError, UnsupportedFolioReviewedViewError, type ValidateDocxConformanceOptions, applyDocxXmlPatchProposal, applyFolioAIEditsToBuffer, applyFolioVersionDiffPrivacy, assertSupportedFolioDocumentOperationVersion, bookmark, compareDocxVersions, createBilingualDocument, createBilingualDocx, createDocx, createEmptyDocument, createFolioAITextRangeHandle, createStellaStyleDocumentPreset, createStellaStyleSet, createTableOfContentsField, deriveBlockId, docxToMarkdown, endnote, ensureParaIds, evaluateDocxXmlPatchProposal, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractDocxText, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, hashFolioAIBlockText, heading, hyperlink, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxPackage, isFolioBlockId, isFolioDocumentOperationModeSupported, isFolioDocumentPrivacyTransform, isFolioResolvedReviewedView, isFolioReviewedView, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, pageBreak, paragraph, parseDocx, parseFolioDocumentOperationBatch, parseFolioDocxXmlPatchProposal, readBilingualDocument, readBilingualDocx, readFolioDocumentSection, replyToComment, rewriteDocxMetadataPrivacy, run, table, validateDocxConformance };
|
|
29
|
+
export { type ApplyDocxXmlPatchProposalArgs, type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, type BilingualBorders, type BilingualParagraphRef, type BilingualRow, type BilingualRowKind, type BilingualTableParagraphRef, type CreateBilingualDocumentOptions, type CreateBilingualDocumentResult, type CreateBilingualDocxOptions, type CreateBilingualDocxResult, type CreateCommentReplyInput, type CreateEmptyDocumentOptions, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, type DeriveBlockIdInput, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, DocxArchiveError, type DocxArchiveOptions, type DocxParagraphSource, type DocxTableRowKind, type DocxTableRowPosition, EnsureParaIdsError, type EnsureParaIdsOptions, type EnsureParaIdsResult, type EvaluateDocxXmlPatchProposalArgs, type ExtractDocumentStyleSetOptions, type ExtractedDocxParagraph, type ExtractedDocxTableCell, type ExtractedDocxTableCellParagraph, type ExtractedDocxText, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLIO_DOCX_CONFORMANCE_PROFILE, FOLIO_DOCX_CONFORMANCE_REPORT_VERSION, FOLIO_DOCX_PACKAGE_INSPECTION_DEFAULTS, FOLIO_DOCX_PACKAGE_INSPECTION_ERROR_CODES, FOLIO_DOCX_PACKAGE_INSPECTION_VERSION, FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FOLIO_DOCX_XML_PATCH_PROPOSAL_DEFAULTS, FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES, FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, FOLIO_DOCX_XML_PATCH_PROPOSAL_VERSION, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditSnapshot, type FolioAIInlineFormatting, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsOptions, type FolioApplyDocumentOperationsToStoryOptions, type FolioApplyOperationsOptions, type FolioBlockDiff, type FolioBlockId, type FolioCompareDocxVersionsOptions, type FolioDocumentMetadataProperty, type FolioDocumentMetadataValue, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, FolioDocumentPrivacyArchiveError, type FolioDocumentPrivacyOptions, type FolioDocumentPrivacyReport, type FolioDocumentPrivacyTransform, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioDocxConformanceCheck, type FolioDocxConformanceCheckId, type FolioDocxConformanceCheckStatus, type FolioDocxConformanceIssue, type FolioDocxConformanceIssueCode, type FolioDocxConformanceReport, type FolioDocxConformanceStatus, type FolioDocxInspectedXmlPart, type FolioDocxPackageInspection, FolioDocxPackageInspectionError, type FolioDocxPackageInspectionErrorCode, type FolioDocxPackageInspectionLimits, type FolioDocxPackagePart, type FolioDocxPackagePartKind, type FolioDocxPreparedXmlReplacement, FolioDocxReviewer, type FolioDocxReviewerOptions, type FolioDocxXmlPatchApplication, FolioDocxXmlPatchApplicationError, type FolioDocxXmlPatchApplicationReceipt, type FolioDocxXmlPatchProposal, type FolioDocxXmlPatchProposalEvaluation, type FolioDocxXmlPatchProposalIssue, type FolioDocxXmlPatchProposalIssueCode, type FolioDocxXmlPatchProposalLimits, type FolioDocxXmlReplacement, type FolioEditableDocumentStoryHandle, type FolioFormatProperty, type FolioMetadataDiff, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeFilter, type FolioReviewChangeKind, type FolioReviewComment, type FolioReviewCommentFilter, type FolioReviewCommentReply, type FolioReviewReplyInput, type FolioReviewedStory, type FolioReviewedView, type FolioStoryDiff, type FolioVersionBlockHandle, type FolioVersionComparisonPrivacyTransform, type FolioVersionComparisonScope, type FolioVersionDiff, type FolioVersionDiffPrivacyOptions, type FolioVersionDiffPrivacyReport, type FolioVersionDiffSegment, type FolioVersionDiffSummaryCounts, type GenerateRedlineDocxOptions, type GenerateRedlineDocxResult, type GenerateRedlineUnprocessedStory, HEADING_LEVELS, type HeadingLevel, type InspectDocxPackageOptions, InvalidBilingualDocumentOptionsError, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, InvalidFolioReportBuilderOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, type ParseOptions, type RewriteDocxMetadataPrivacyResult, STELLA_STYLE_SET_NAME, type TableCellSpec, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioDocxXmlPatchApplicationProfileError, UnsupportedFolioReviewedViewError, type ValidateDocxConformanceOptions, applyDocxXmlPatchProposal, applyFolioAIEditsToBuffer, applyFolioVersionDiffPrivacy, assertSupportedFolioDocumentOperationVersion, bookmark, compareDocxVersions, createBilingualDocument, createBilingualDocx, createDocx, createEmptyDocument, createFolioAITextRangeHandle, createStellaStyleDocumentPreset, createStellaStyleSet, createTableOfContentsField, deriveBlockId, docxToMarkdown, endnote, ensureParaIds, evaluateDocxXmlPatchProposal, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractDocxText, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, hashFolioAIBlockText, heading, hyperlink, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxPackage, isFolioBlockId, isFolioDocumentOperationModeSupported, isFolioDocumentPrivacyTransform, isFolioResolvedReviewedView, isFolioReviewedView, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, pageBreak, paragraph, parseDocx, parseFolioDocumentOperationBatch, parseFolioDocxXmlPatchProposal, readBilingualDocument, readBilingualDocx, readFolioDocumentSection, replyToComment, rewriteDocxMetadataPrivacy, run, table, validateDocxConformance };
|
package/dist/types/content.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign } from "@stll/docx-core/model";
|
|
2
|
-
export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign };
|
|
1
|
+
import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, DrawingRawXmlMode, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign } from "@stll/docx-core/model";
|
|
2
|
+
export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, DrawingRawXmlMode, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ type DocumentBody = document_d_exports.DocumentBody;
|
|
|
16
16
|
type DocxConformanceClass = document_d_exports.DocxConformanceClass;
|
|
17
17
|
type DocxPackage = document_d_exports.DocxPackage;
|
|
18
18
|
type DrawingContent = document_d_exports.DrawingContent;
|
|
19
|
+
type DrawingRawXmlMode = document_d_exports.DrawingRawXmlMode;
|
|
19
20
|
type EmphasisMark = document_d_exports.EmphasisMark;
|
|
20
21
|
type Endnote = document_d_exports.Endnote;
|
|
21
22
|
type EndnotePosition = document_d_exports.EndnotePosition;
|
|
@@ -72,6 +73,7 @@ type ShadingProperties = document_d_exports.ShadingProperties;
|
|
|
72
73
|
type Shape = document_d_exports.Shape;
|
|
73
74
|
type ShapeContent = document_d_exports.ShapeContent;
|
|
74
75
|
type ShapeFill = document_d_exports.ShapeFill;
|
|
76
|
+
type ShapeGeometryAdjustment = document_d_exports.ShapeGeometryAdjustment;
|
|
75
77
|
type ShapeOutline = document_d_exports.ShapeOutline;
|
|
76
78
|
type ShapeTextBody = document_d_exports.ShapeTextBody;
|
|
77
79
|
type ShapeType = document_d_exports.ShapeType;
|
|
@@ -106,4 +108,4 @@ type ThemeFont = document_d_exports.ThemeFont;
|
|
|
106
108
|
type ThemeFontScheme = document_d_exports.ThemeFontScheme;
|
|
107
109
|
type UnderlineStyle = document_d_exports.UnderlineStyle;
|
|
108
110
|
type VerticalAlign = document_d_exports.VerticalAlign;
|
|
109
|
-
export type { AbstractNumbering, BlockContent, BookmarkEnd, BookmarkStart, BorderSpec, BreakContent, CellMargins, ColorValue, Column, ComplexField, ConditionalFormatStyle, DocDefaults, Document, DocumentBody, DocxConformanceClass, DocxPackage, DrawingContent, EmphasisMark, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FloatingTableProperties, FontInfo, FontTable, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InstrTextContent, LevelSuffix, LineNumberRestart, LineSpacingRule, ListLevel, ListRendering, MediaFile, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, NumberFormat, NumberingDefinitions, NumberingInstance, PageOrientation, Paragraph, ParagraphAlignment, ParagraphContent, ParagraphFormatting, PositionalTab, Relationship, RelationshipMap, RelationshipType, Run, RunContent, Section, SectionProperties, SectionStart, ShadingProperties, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, Style, StyleDefinitions, StyleType, SymbolContent, TabContent, TabLeader, TabStop, TabStopAlignment, Table, TableBorders, TableCell, TableCellFormatting, TableFormatting, TableLook, TableMeasurement, TableRow, TableRowFormatting, TableWidthType, TextBox, TextContent, TextEffect, TextFormatting, Theme, ThemeColorScheme, ThemeColorSlot, ThemeFont, ThemeFontScheme, UnderlineStyle, VerticalAlign };
|
|
111
|
+
export type { AbstractNumbering, BlockContent, BookmarkEnd, BookmarkStart, BorderSpec, BreakContent, CellMargins, ColorValue, Column, ComplexField, ConditionalFormatStyle, DocDefaults, Document, DocumentBody, DocxConformanceClass, DocxPackage, DrawingContent, DrawingRawXmlMode, EmphasisMark, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FloatingTableProperties, FontInfo, FontTable, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InstrTextContent, LevelSuffix, LineNumberRestart, LineSpacingRule, ListLevel, ListRendering, MediaFile, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, NumberFormat, NumberingDefinitions, NumberingInstance, PageOrientation, Paragraph, ParagraphAlignment, ParagraphContent, ParagraphFormatting, PositionalTab, Relationship, RelationshipMap, RelationshipType, Run, RunContent, Section, SectionProperties, SectionStart, ShadingProperties, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, Style, StyleDefinitions, StyleType, SymbolContent, TabContent, TabLeader, TabStop, TabStopAlignment, Table, TableBorders, TableCell, TableCellFormatting, TableFormatting, TableLook, TableMeasurement, TableRow, TableRowFormatting, TableWidthType, TextBox, TextContent, TextEffect, TextFormatting, Theme, ThemeColorScheme, ThemeColorSlot, ThemeFont, ThemeFontScheme, UnderlineStyle, VerticalAlign };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/utils/tableOfContentsStyle.d.ts
|
|
2
|
+
type TableOfContentsStyleIdentity = {
|
|
3
|
+
styleId: string | undefined;
|
|
4
|
+
styleName?: string;
|
|
5
|
+
};
|
|
6
|
+
/** Resolve a built-in TOC entry style without relying on its localized style id. */
|
|
7
|
+
declare const tableOfContentsStyleLevel: ({ styleId, styleName }: TableOfContentsStyleIdentity) => number | undefined;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { tableOfContentsStyleLevel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/utils/tableOfContentsStyle.ts
|
|
2
|
+
const TABLE_OF_CONTENTS_STYLE_ID = /^TOC(?<level>\d*)$/iu;
|
|
3
|
+
const TABLE_OF_CONTENTS_STYLE_NAME = /^toc\s+(?<level>\d+)$/iu;
|
|
4
|
+
const parsedLevel = (match) => {
|
|
5
|
+
if (!match) return;
|
|
6
|
+
const rawLevel = match.groups?.["level"];
|
|
7
|
+
if (rawLevel === "") return 1;
|
|
8
|
+
const level = Number(rawLevel);
|
|
9
|
+
return Number.isSafeInteger(level) && level > 0 ? level : void 0;
|
|
10
|
+
};
|
|
11
|
+
/** Resolve a built-in TOC entry style without relying on its localized style id. */
|
|
12
|
+
const tableOfContentsStyleLevel = ({ styleId, styleName }) => parsedLevel(TABLE_OF_CONTENTS_STYLE_ID.exec(styleId ?? "")) ?? parsedLevel(TABLE_OF_CONTENTS_STYLE_NAME.exec(styleName ?? ""));
|
|
13
|
+
//#endregion
|
|
14
|
+
export { tableOfContentsStyleLevel };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"document-model",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"perf": "bun scripts/profile-editor.ts"
|
|
114
114
|
},
|
|
115
115
|
"dependencies": {
|
|
116
|
-
"@stll/docx-core": "^0.17.
|
|
116
|
+
"@stll/docx-core": "^0.17.1",
|
|
117
117
|
"@stll/docx-utils": "^0.1.0",
|
|
118
118
|
"@stll/template-conditions": "^0.1.0",
|
|
119
119
|
"better-result": "3.0.1",
|