@stll/folio-core 0.21.0 → 0.22.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.
@@ -6,7 +6,7 @@ import { assertValidFolioDocumentModel } from "./modelValidation.js";
6
6
  import { isNewDataUrlDrawing } from "./newImage.js";
7
7
  import { parseNumbering } from "./numberingParser.js";
8
8
  import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
9
- import { buildParagraphOffsetIndex, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
9
+ import { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
10
10
  import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
11
11
  import { serializeDocument } from "./serializer/documentSerializer.js";
12
12
  import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
@@ -14,7 +14,7 @@ import { serializeHeaderFooter } from "./serializer/headerFooterSerializer.js";
14
14
  import { serializeEndnotes, serializeFootnotes, serializeNewEndnotesPart, serializeNewFootnotesPart } from "./serializer/noteSerializer.js";
15
15
  import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
16
16
  import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
17
- import { serializeStylesXml } from "./serializer/stylesSerializer.js";
17
+ import { serializeStyle, serializeStylesXml } from "./serializer/stylesSerializer.js";
18
18
  import { serializeThemeXml } from "./serializer/themeSerializer.js";
19
19
  import { escapeXml } from "./serializer/xmlUtils.js";
20
20
  import { isPreservableDocxEntry } from "./unzip.js";
@@ -450,6 +450,7 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
450
450
  serializeHeadersFootersToZip(document, outputZip, compressionLevel);
451
451
  await serializeNotesToZip(document, originalZip, outputZip, compressionLevel);
452
452
  await serializeNumberingIntoZip(document, originalZip, outputZip, compressionLevel);
453
+ await serializeAddedStylesIntoZip(document, originalZip, outputZip, compressionLevel);
453
454
  await serializeCommentsToZip(document, outputZip, compressionLevel);
454
455
  if (updateModifiedDate && originalCorePropertiesXml) {
455
456
  const updatedCoreProperties = updateCoreProperties(originalCorePropertiesXml, {
@@ -530,6 +531,7 @@ async function repackDocxFromRaw(doc, rawContent, options = {}) {
530
531
  serializeHeadersFootersToZip(exportDocument, newZip, compressionLevel);
531
532
  await serializeNotesToZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
532
533
  await serializeNumberingIntoZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
534
+ await serializeAddedStylesIntoZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
533
535
  await serializeCommentsToZip(exportDocument, newZip, compressionLevel);
534
536
  if (updateModifiedDate && rawContent.corePropsXml) {
535
537
  const updatedCoreProps = updateCoreProperties(rawContent.corePropsXml, {
@@ -1081,14 +1083,56 @@ async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLe
1081
1083
  }
1082
1084
  const currentXml = serializeNumberingXml(numbering);
1083
1085
  const changed = collectChangedNumberingDefs(baseline.serializedXml, currentXml);
1084
- if (changed.abstractNums.size === 0 && changed.nums.size === 0) return;
1085
- const patched = buildPatchedNumberingXml(baseline.originalXml, currentXml, changed);
1086
+ const added = collectAddedNumberingDefs(baseline.serializedXml, currentXml);
1087
+ const hasChanged = changed.abstractNums.size > 0 || changed.nums.size > 0;
1088
+ const hasAdded = added.abstractNums.size > 0 || added.nums.size > 0;
1089
+ if (!hasChanged && !hasAdded) return;
1090
+ const spliced = buildPatchedNumberingXml(baseline.originalXml, currentXml, changed);
1091
+ if (spliced === null) return;
1092
+ const patched = appendNumberingDefs(spliced, currentXml, added);
1086
1093
  if (patched === null) return;
1087
1094
  newZip.file(file.name, patched, {
1088
1095
  compression: "DEFLATE",
1089
1096
  compressionOptions: { level: compressionLevel }
1090
1097
  });
1091
1098
  }
1099
+ const STYLES_PART_PATH = "word/styles.xml";
1100
+ const STYLES_CLOSE_ROOT = "</w:styles>";
1101
+ const STYLE_ID_PATTERN = /<w:style\b[^>]*?\bw:styleId="(?<id>[^"]+)"/gu;
1102
+ /**
1103
+ * Append styles the model defines but the original `word/styles.xml` lacks.
1104
+ * Existing styles stay byte-exact (edits to them are not written here, the
1105
+ * part is otherwise preserved verbatim); only minted definitions, such as the
1106
+ * per-language clones a bilingual transform adds, are emitted before the root
1107
+ * close so paragraphs referencing them resolve on reopen.
1108
+ */
1109
+ async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compressionLevel) {
1110
+ const styles = doc.package.styles;
1111
+ if (!styles || styles.styles.length === 0) return;
1112
+ const file = findNotePartEntry(originalZip, STYLES_PART_PATH);
1113
+ const originalXml = file ? await file.async("text") : null;
1114
+ const rootClose = originalXml?.lastIndexOf(STYLES_CLOSE_ROOT) ?? -1;
1115
+ if (file === null || originalXml === null || rootClose < 0) {
1116
+ await materializeNewNotePart({
1117
+ contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
1118
+ newZip,
1119
+ partPath: STYLES_PART_PATH,
1120
+ relationshipType: RELATIONSHIP_TYPES.styles,
1121
+ serializedPart: serializeStylesXml(styles),
1122
+ compressionLevel
1123
+ });
1124
+ return;
1125
+ }
1126
+ const existing = /* @__PURE__ */ new Set();
1127
+ for (const match of originalXml.matchAll(STYLE_ID_PATTERN)) existing.add(match.groups["id"]);
1128
+ const added = styles.styles.filter((style) => !existing.has(style.styleId));
1129
+ if (added.length === 0) return;
1130
+ const patched = originalXml.slice(0, rootClose) + added.map(serializeStyle).join("") + originalXml.slice(rootClose);
1131
+ newZip.file(file.name, patched, {
1132
+ compression: "DEFLATE",
1133
+ compressionOptions: { level: compressionLevel }
1134
+ });
1135
+ }
1092
1136
  async function patchNotePartIntoZip(conventionalLowerPath, currentXml, baselineFrom, originalZip, newZip, compressionLevel) {
1093
1137
  const file = findNotePartEntry(originalZip, conventionalLowerPath);
1094
1138
  if (!file) return;
@@ -129,5 +129,23 @@ declare function collectChangedNumberingDefs(baselineXml: string, currentXml: st
129
129
  * in either input (so the caller preserves the original part verbatim).
130
130
  */
131
131
  declare function buildPatchedNumberingXml(originalXml: string, currentXml: string, changed: ChangedNumberingDefs): string | null;
132
+ /**
133
+ * Numbering definitions present in `currentXml` (the model's serialization)
134
+ * but absent from `baselineXml` (the re-parsed original): definitions a
135
+ * transform minted. `collectChangedNumberingDefs` deliberately skips these
136
+ * because they cannot be spliced by id; they are appended instead.
137
+ */
138
+ declare function collectAddedNumberingDefs(baselineXml: string, currentXml: string): ChangedNumberingDefs;
139
+ /**
140
+ * Append added `w:abstractNum` / `w:num` definitions from `currentXml` to
141
+ * `xml`. ECMA-376 §17.9 orders every `w:abstractNum` before the first `w:num`,
142
+ * so abstract definitions go right before the first `<w:num ` (or the root
143
+ * close when the part has none) and instances before the root close. A
144
+ * synthetic numFmt in an added abstract is restored from the original
145
+ * definition it was cloned from (the one with an identical body), so a custom
146
+ * format survives cloning. Returns null when an added id cannot be extracted
147
+ * or the part has no `</w:numbering>`.
148
+ */
149
+ declare function appendNumberingDefs(xml: string, currentXml: string, added: ChangedNumberingDefs): string | null;
132
150
  //#endregion
133
- export { ChangedNumberingDefs, ParagraphOffsets, PatchSafetyOptions, PatchValidationResult, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
151
+ export { ChangedNumberingDefs, ParagraphOffsets, PatchSafetyOptions, PatchValidationResult, appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
@@ -552,8 +552,79 @@ function buildPatchedNumberingXml(originalXml, currentXml, changed) {
552
552
  for (const { start, end, newXml } of replacements) result = result.slice(0, start) + newXml + result.slice(end);
553
553
  return result;
554
554
  }
555
+ /**
556
+ * Numbering definitions present in `currentXml` (the model's serialization)
557
+ * but absent from `baselineXml` (the re-parsed original): definitions a
558
+ * transform minted. `collectChangedNumberingDefs` deliberately skips these
559
+ * because they cannot be spliced by id; they are appended instead.
560
+ */
561
+ function collectAddedNumberingDefs(baselineXml, currentXml) {
562
+ const addedForKind = (kind) => {
563
+ const added = /* @__PURE__ */ new Set();
564
+ const baselineIndex = buildNumberingElementOffsetIndex(baselineXml, kind);
565
+ const currentIndex = buildNumberingElementOffsetIndex(currentXml, kind);
566
+ for (const [id, range] of currentIndex) if (range && !baselineIndex.has(id)) added.add(id);
567
+ return added;
568
+ };
569
+ return {
570
+ abstractNums: addedForKind("abstractNum"),
571
+ nums: addedForKind("num")
572
+ };
573
+ }
574
+ const NUMBERING_CLOSE_ROOT = "</w:numbering>";
575
+ /**
576
+ * Append added `w:abstractNum` / `w:num` definitions from `currentXml` to
577
+ * `xml`. ECMA-376 §17.9 orders every `w:abstractNum` before the first `w:num`,
578
+ * so abstract definitions go right before the first `<w:num ` (or the root
579
+ * close when the part has none) and instances before the root close. A
580
+ * synthetic numFmt in an added abstract is restored from the original
581
+ * definition it was cloned from (the one with an identical body), so a custom
582
+ * format survives cloning. Returns null when an added id cannot be extracted
583
+ * or the part has no `</w:numbering>`.
584
+ */
585
+ function appendNumberingDefs(xml, currentXml, added) {
586
+ if (added.abstractNums.size === 0 && added.nums.size === 0) return xml;
587
+ const rootClose = xml.lastIndexOf(NUMBERING_CLOSE_ROOT);
588
+ if (rootClose < 0) return null;
589
+ const abstractXmls = [];
590
+ for (const id of added.abstractNums) {
591
+ const def = extractNumberingElementXml(currentXml, "abstractNum", id);
592
+ if (def === null) return null;
593
+ abstractXmls.push(restoreClonedLevelNumFmts(xml, currentXml, def, id));
594
+ }
595
+ const numXmls = [];
596
+ for (const id of added.nums) {
597
+ const def = extractNumberingElementXml(currentXml, "num", id);
598
+ if (def === null) return null;
599
+ numXmls.push(def);
600
+ }
601
+ const firstNum = findFirstElement(xml, NUMBERING_OPEN_LITERAL.num, NUMBERING_CLOSE_TAG.num);
602
+ const abstractInsertAt = firstNum ? firstNum.start : rootClose;
603
+ const head = xml.slice(0, abstractInsertAt);
604
+ const middle = xml.slice(abstractInsertAt, rootClose);
605
+ const tail = xml.slice(rootClose);
606
+ return head + abstractXmls.join("") + middle + numXmls.join("") + tail;
607
+ }
608
+ /**
609
+ * For an added abstract definition that still carries a synthetic numFmt, find
610
+ * the original abstract it was cloned from (same serialized body apart from the
611
+ * id) and restore the level formats from it.
612
+ */
613
+ function restoreClonedLevelNumFmts(originalXml, currentXml, addedDefXml, addedId) {
614
+ if (!SYNTHETIC_NUM_FMT_PATTERN.test(addedDefXml)) return addedDefXml;
615
+ const addedBody = stripAbstractNumId(addedDefXml, addedId);
616
+ const originalIds = collectElementIds(originalXml, NUMBERING_OPEN_LITERAL.abstractNum, NUMBERING_ID_ATTR.abstractNum);
617
+ for (const [id] of originalIds) {
618
+ const candidate = extractNumberingElementXml(currentXml, "abstractNum", id);
619
+ if (candidate === null || stripAbstractNumId(candidate, id) !== addedBody) continue;
620
+ const originalDef = extractNumberingElementXml(originalXml, "abstractNum", id);
621
+ if (originalDef !== null) return restoreLevelNumFmts(originalDef, addedDefXml);
622
+ }
623
+ return restoreLevelNumFmts("", addedDefXml);
624
+ }
625
+ const stripAbstractNumId = (defXml, id) => defXml.replace(`${NUMBERING_ID_ATTR.abstractNum}="${id}"`, "");
555
626
  function escapeRegExp(str) {
556
627
  return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
557
628
  }
558
629
  //#endregion
559
- export { buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
630
+ export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
@@ -1,5 +1,6 @@
1
1
  import { document_d_exports } from "../../types/document.js";
2
2
  //#region src/docx/serializer/stylesSerializer.d.ts
3
3
  declare const serializeStylesXml: (definitions: document_d_exports.StyleDefinitions) => string;
4
+ declare const serializeStyle: (style: document_d_exports.Style) => string;
4
5
  //#endregion
5
- export { serializeStylesXml };
6
+ export { serializeStyle, serializeStylesXml };
@@ -53,4 +53,4 @@ const pushBooleanAttr = (attrs, name, value) => {
53
53
  if (value !== void 0) attrs.push(`${name}="${value ? 1 : 0}"`);
54
54
  };
55
55
  //#endregion
56
- export { serializeStylesXml };
56
+ export { serializeStyle, serializeStylesXml };
@@ -0,0 +1,62 @@
1
+ import { document_d_exports } from "../../types/document.js";
2
+ //#region src/docx/server/createBilingualDocument.d.ts
3
+ type BilingualRowKind = "paragraph" | "heading" | "listItem";
4
+ /** One translatable unit: a source paragraph and its right-column copy. */
5
+ type BilingualParagraphRef = {
6
+ /** `paraId` of the untouched source paragraph (left column). */
7
+ sourceParaId: string | undefined;
8
+ /** `paraId` minted for the right-column copy; stable across re-runs. */
9
+ targetParaId: string;
10
+ /** Plain text of the source paragraph. */
11
+ sourceText: string;
12
+ };
13
+ type BilingualRow = ({
14
+ kind: BilingualRowKind;
15
+ /** Equals `targetParaId`; the handle callers use to address the row. */
16
+ rowId: string;
17
+ } & BilingualParagraphRef) | {
18
+ kind: "table";
19
+ rowId: string;
20
+ /**
21
+ * Every paragraph inside the table, in document order. The table is not
22
+ * copied, so these are the paragraphs to translate in place.
23
+ */
24
+ paragraphs: BilingualTableParagraphRef[];
25
+ };
26
+ type BilingualTableParagraphRef = {
27
+ paraId: string | undefined;
28
+ sourceText: string;
29
+ };
30
+ type BilingualBorders = "none" | "grid";
31
+ type CreateBilingualDocumentOptions = {
32
+ /**
33
+ * Suffix for cloned style ids and names (for example `"en"` turns
34
+ * `Heading1` into `Heading1-en`). Must be a non-empty token of letters,
35
+ * digits, or `-`.
36
+ */
37
+ targetStyleSuffix: string;
38
+ /** Table borders; legal practice is usually `"none"`. Default `"none"`. */
39
+ borders?: BilingualBorders;
40
+ };
41
+ type CreateBilingualDocumentResult = {
42
+ document: document_d_exports.Document;
43
+ rows: BilingualRow[];
44
+ /** Non-fatal fidelity notes (for example an unresolvable numbering style link). */
45
+ warnings: string[];
46
+ };
47
+ declare const InvalidBilingualDocumentOptionsError_base: import("better-result").TaggedErrorClass<"InvalidBilingualDocumentOptionsError", {
48
+ message: string;
49
+ option: "targetStyleSuffix";
50
+ }>;
51
+ declare class InvalidBilingualDocumentOptionsError extends InvalidBilingualDocumentOptionsError_base {}
52
+ declare function createBilingualDocument(source: document_d_exports.Document, options: CreateBilingualDocumentOptions): CreateBilingualDocumentResult;
53
+ /**
54
+ * Re-derive the row manifest from a document produced by
55
+ * {@link createBilingualDocument}. Detection is structural: a top-level table
56
+ * whose rows are all either a left | right pair of single-paragraph cells or
57
+ * one cell spanning both columns. Rows are returned in document order; the
58
+ * right paragraph's `paraId` is the row handle, as at creation.
59
+ */
60
+ declare function readBilingualDocument(document: document_d_exports.Document): BilingualRow[];
61
+ //#endregion
62
+ export { BilingualBorders, BilingualParagraphRef, BilingualRow, BilingualRowKind, BilingualTableParagraphRef, CreateBilingualDocumentOptions, CreateBilingualDocumentResult, InvalidBilingualDocumentOptionsError, createBilingualDocument, readBilingualDocument };
@@ -0,0 +1,511 @@
1
+ import { deterministicHexId } from "../../utils/hexId.js";
2
+ import { getParagraphText } from "../paragraphParser.js";
3
+ import { TaggedError } from "better-result";
4
+ //#region src/docx/server/createBilingualDocument.ts
5
+ /**
6
+ * Bilingual document transform: body -> two-column table, one row per block.
7
+ *
8
+ * The left column keeps every source block untouched; the right column holds a
9
+ * copy of the same block whose numbering and numbered paragraph styles are
10
+ * cloned per language, so both columns count independently (1. / 1. instead of
11
+ * 1. / 2.) and stay live in Word. Right-column paragraphs receive fresh
12
+ * `paraId`s so callers can address each row later (for example to replace the
13
+ * placeholder copy with a translation by block id).
14
+ *
15
+ * Section breaks cannot live inside a table cell, so the body is split at
16
+ * paragraphs carrying `sectionProperties`: each section becomes its own table
17
+ * and the break paragraph stays between the tables. A source table (parties,
18
+ * signature block) is kept once, in a row spanning both columns: it is signed
19
+ * and read once, and its labels are translated inline rather than duplicated.
20
+ */
21
+ const STYLE_SUFFIX_PATTERN = /^[A-Za-z0-9-]+$/u;
22
+ var InvalidBilingualDocumentOptionsError = class extends TaggedError("InvalidBilingualDocumentOptionsError")() {};
23
+ const FULL_WIDTH_PCT = 5e3;
24
+ const HALF_WIDTH_PCT = 2500;
25
+ const A4_TEXT_WIDTH_TWIPS = 9072;
26
+ const ROW_ID_NAMESPACE = "folio-bilingual";
27
+ const GRID_BORDER = {
28
+ style: "single",
29
+ size: 4,
30
+ space: 0
31
+ };
32
+ const TABLE_BORDERS = {
33
+ none: {
34
+ top: { style: "nil" },
35
+ bottom: { style: "nil" },
36
+ left: { style: "nil" },
37
+ right: { style: "nil" },
38
+ insideH: { style: "nil" },
39
+ insideV: { style: "nil" }
40
+ },
41
+ grid: {
42
+ top: GRID_BORDER,
43
+ bottom: GRID_BORDER,
44
+ left: GRID_BORDER,
45
+ right: GRID_BORDER,
46
+ insideH: GRID_BORDER,
47
+ insideV: GRID_BORDER
48
+ }
49
+ };
50
+ function createBilingualDocument(source, options) {
51
+ if (!STYLE_SUFFIX_PATTERN.test(options.targetStyleSuffix)) throw new InvalidBilingualDocumentOptionsError({
52
+ message: `targetStyleSuffix must match ${STYLE_SUFFIX_PATTERN}; received ${JSON.stringify(options.targetStyleSuffix)}`,
53
+ option: "targetStyleSuffix"
54
+ });
55
+ const borders = options.borders ?? "none";
56
+ const warnings = [];
57
+ const styles = source.package.styles;
58
+ const numbering = source.package.numbering;
59
+ const styleById = new Map((styles?.styles ?? []).map((style) => [style.styleId, style]));
60
+ const blocks = flattenBlocks(source.package.document.content);
61
+ const cloner = createNumberingCloner({
62
+ numbering,
63
+ styleById,
64
+ warnings
65
+ });
66
+ const styleCloner = createStyleCloner({
67
+ styleById,
68
+ suffix: options.targetStyleSuffix,
69
+ cloner
70
+ });
71
+ const paraIds = createParaIdMinter(collectPackageParaIds(source.package));
72
+ const rows = [];
73
+ const content = [];
74
+ let sectionRows = [];
75
+ const textWidth = resolveTextWidthTwips(source);
76
+ const flushSection = () => {
77
+ if (sectionRows.length > 0) content.push(buildTable(sectionRows, borders, textWidth));
78
+ sectionRows = [];
79
+ };
80
+ const copyParagraph = (paragraph) => {
81
+ const targetParaId = paraIds.mint(paragraph.paraId);
82
+ return {
83
+ copy: cloneParagraphForTarget(paragraph, targetParaId, styleCloner, cloner),
84
+ ref: {
85
+ sourceParaId: paragraph.paraId,
86
+ targetParaId,
87
+ sourceText: getParagraphText(paragraph)
88
+ }
89
+ };
90
+ };
91
+ for (const block of blocks) {
92
+ if (block.type === "paragraph" && block.sectionProperties) {
93
+ flushSection();
94
+ content.push(block);
95
+ continue;
96
+ }
97
+ if (block.type === "paragraph") {
98
+ if (isEmptyParagraph(block)) continue;
99
+ const { copy, ref } = copyParagraph(block);
100
+ rows.push({
101
+ kind: classifyParagraph(block, styleById),
102
+ rowId: ref.targetParaId,
103
+ ...ref
104
+ });
105
+ sectionRows.push(buildRow(block, copy));
106
+ continue;
107
+ }
108
+ const paragraphs = collectTableParagraphs(block).map((paragraph) => ({
109
+ paraId: paragraph.paraId,
110
+ sourceText: getParagraphText(paragraph)
111
+ }));
112
+ rows.push({
113
+ kind: "table",
114
+ rowId: paragraphs.at(0)?.paraId ?? tableRowHandle(rows.length),
115
+ paragraphs
116
+ });
117
+ sectionRows.push(buildSpanningRow(block));
118
+ }
119
+ flushSection();
120
+ return {
121
+ document: {
122
+ ...source,
123
+ package: {
124
+ ...source.package,
125
+ document: {
126
+ ...source.package.document,
127
+ content
128
+ },
129
+ ...cloner.hasClones() && { numbering: cloner.toDefinitions() },
130
+ ...styleCloner.hasClones() && styles && { styles: styleCloner.toDefinitions(styles) }
131
+ }
132
+ },
133
+ rows,
134
+ warnings
135
+ };
136
+ }
137
+ /** Handle for a table row whose paragraphs carry no `paraId`: its position in
138
+ * the manifest, which creation and reading derive identically. */
139
+ const tableRowHandle = (index) => `table-${index}`;
140
+ /** Top-level body blocks with content controls flattened to their children. */
141
+ const flattenBlocks = (content) => {
142
+ const out = [];
143
+ const visit = (block) => {
144
+ if (block.type === "paragraph" || block.type === "table") {
145
+ out.push(block);
146
+ return;
147
+ }
148
+ for (const child of block.content) visit(child);
149
+ };
150
+ for (const block of content) visit(block);
151
+ return out;
152
+ };
153
+ const isEmptyParagraph = (paragraph) => {
154
+ if (getParagraphText(paragraph).trim().length > 0) return false;
155
+ return paragraph.content.every((item) => item.type === "run" && item.content.every((part) => part.type === "text"));
156
+ };
157
+ /** Heading style families across Word UI languages (en, cs/sk, de, fr, pl). */
158
+ const HEADING_STYLE_PATTERN = /heading|nadpis|berschrift|titre|nag[łl]/iu;
159
+ const classifyParagraph = (paragraph, styleById) => {
160
+ const formatting = paragraph.formatting;
161
+ const style = formatting?.styleId ? styleById.get(formatting.styleId) : void 0;
162
+ const outlineLevel = formatting?.outlineLevel ?? resolveInheritedOutlineLevel(style, styleById);
163
+ if (outlineLevel !== void 0 && outlineLevel < 9) return "heading";
164
+ if (style && (HEADING_STYLE_PATTERN.test(style.styleId) || HEADING_STYLE_PATTERN.test(style.name ?? ""))) return "heading";
165
+ if (effectiveNumPr(paragraph, styleById) !== void 0) return "listItem";
166
+ return "paragraph";
167
+ };
168
+ const resolveInheritedOutlineLevel = (style, styleById) => {
169
+ const seen = /* @__PURE__ */ new Set();
170
+ let current = style;
171
+ while (current && !seen.has(current.styleId)) {
172
+ seen.add(current.styleId);
173
+ if (current.pPr?.outlineLevel !== void 0) return current.pPr.outlineLevel;
174
+ current = current.basedOn ? styleById.get(current.basedOn) : void 0;
175
+ }
176
+ };
177
+ /** The numbering a paragraph renders with: direct `numPr`, else the style chain's. */
178
+ const effectiveNumPr = (paragraph, styleById) => {
179
+ const direct = paragraph.formatting?.numPr;
180
+ if (direct?.numId !== void 0) return direct.numId === 0 ? void 0 : direct;
181
+ const styleId = paragraph.formatting?.styleId;
182
+ return styleId ? styleNumPr(styleById.get(styleId), styleById) : void 0;
183
+ };
184
+ const styleNumPr = (style, styleById) => {
185
+ const seen = /* @__PURE__ */ new Set();
186
+ let current = style;
187
+ while (current && !seen.has(current.styleId)) {
188
+ seen.add(current.styleId);
189
+ const numPr = current.pPr?.numPr;
190
+ if (numPr?.numId !== void 0) return numPr.numId === 0 ? void 0 : numPr;
191
+ current = current.basedOn ? styleById.get(current.basedOn) : void 0;
192
+ }
193
+ };
194
+ const createNumberingCloner = ({ numbering, styleById, warnings }) => {
195
+ const abstractNums = numbering?.abstractNums ?? [];
196
+ const nums = numbering?.nums ?? [];
197
+ const abstractById = new Map(abstractNums.map((item) => [item.abstractNumId, item]));
198
+ const numById = new Map(nums.map((item) => [item.numId, item]));
199
+ let nextAbstractNumId = Math.max(0, ...abstractNums.map((item) => item.abstractNumId)) + 1;
200
+ let nextNumId = Math.max(0, ...nums.map((item) => item.numId)) + 1;
201
+ const clonedAbstract = /* @__PURE__ */ new Map();
202
+ const clonedNum = /* @__PURE__ */ new Map();
203
+ /**
204
+ * Word keys list counters by the abstract definition a `w:num` points at;
205
+ * two instances sharing one abstract continue the same sequence. A clone
206
+ * therefore needs its own abstract, and an abstract that only links to a
207
+ * numbering style must be materialized from that style's levels, otherwise
208
+ * both clones resolve to the same linked definition and share counters.
209
+ */
210
+ const cloneAbstract = (sourceId) => {
211
+ const existing = clonedAbstract.get(sourceId);
212
+ if (existing) return existing;
213
+ const source = abstractById.get(sourceId);
214
+ if (!source) return;
215
+ const resolved = resolveLinkedAbstract(source);
216
+ const { numStyleLink: _numStyleLink, styleLink: _styleLink, ...rest } = resolved;
217
+ const clone = {
218
+ ...rest,
219
+ abstractNumId: nextAbstractNumId,
220
+ levels: structuredClone(resolved.levels)
221
+ };
222
+ nextAbstractNumId += 1;
223
+ clonedAbstract.set(sourceId, clone);
224
+ return clone;
225
+ };
226
+ const resolveLinkedAbstract = (abstract) => {
227
+ const seen = /* @__PURE__ */ new Set();
228
+ let current = abstract;
229
+ while (current.numStyleLink && !seen.has(current.abstractNumId)) {
230
+ seen.add(current.abstractNumId);
231
+ const linkedNumId = styleById.get(current.numStyleLink)?.pPr?.numPr?.numId;
232
+ const linkedNum = linkedNumId === void 0 ? void 0 : numById.get(linkedNumId);
233
+ const linkedAbstract = linkedNum ? abstractById.get(linkedNum.abstractNumId) : void 0;
234
+ if (!linkedAbstract) {
235
+ warnings.push(`Numbering style link "${current.numStyleLink}" on abstractNum ${current.abstractNumId} could not be resolved; the clone keeps the link.`);
236
+ return current;
237
+ }
238
+ current = linkedAbstract;
239
+ }
240
+ return current;
241
+ };
242
+ const cloneNumId = (numId) => {
243
+ const existing = clonedNum.get(numId);
244
+ if (existing) return existing.numId;
245
+ const source = numById.get(numId);
246
+ if (!source) {
247
+ warnings.push(`Numbering instance ${numId} is not defined; paragraphs using it keep the source instance.`);
248
+ return numId;
249
+ }
250
+ const abstract = cloneAbstract(source.abstractNumId);
251
+ if (!abstract) warnings.push(`Numbering instance ${numId} references abstractNum ${source.abstractNumId}, which is not defined; its copy shares the source counters.`);
252
+ const clone = {
253
+ ...source,
254
+ numId: nextNumId,
255
+ abstractNumId: abstract ? abstract.abstractNumId : source.abstractNumId
256
+ };
257
+ nextNumId += 1;
258
+ clonedNum.set(numId, clone);
259
+ return clone.numId;
260
+ };
261
+ return {
262
+ cloneNumId,
263
+ clonedAbstractNumId: (abstractNumId) => clonedAbstract.get(abstractNumId)?.abstractNumId,
264
+ hasClones: () => clonedNum.size > 0,
265
+ toDefinitions: () => ({
266
+ abstractNums: [...abstractNums, ...clonedAbstract.values()],
267
+ nums: [...nums, ...clonedNum.values()]
268
+ })
269
+ };
270
+ };
271
+ /**
272
+ * A paragraph style is cloned only when its chain carries numbering. The clone
273
+ * keeps `basedOn` and every other property; only `pPr.numPr` is rewritten to
274
+ * the cloned instance, so indent precedence stays "style-sourced" exactly as
275
+ * in the source (see `ParagraphFormatting.numPrFromStyle`).
276
+ */
277
+ const createStyleCloner = ({ styleById, suffix, cloner }) => {
278
+ const clones = /* @__PURE__ */ new Map();
279
+ const styleIdFor = (styleId) => {
280
+ const existing = clones.get(styleId);
281
+ if (existing) return existing.styleId;
282
+ const style = styleById.get(styleId);
283
+ if (!style || style.type !== "paragraph") return styleId;
284
+ const numPr = styleNumPr(style, styleById);
285
+ if (numPr?.numId === void 0) return styleId;
286
+ const cloneId = `${styleId}-${suffix}`;
287
+ if (styleById.has(cloneId)) return cloneId;
288
+ const clone = {
289
+ ...style,
290
+ styleId: cloneId,
291
+ name: `${style.name ?? style.styleId} (${suffix})`,
292
+ ...style.next !== void 0 && { next: style.next === styleId ? cloneId : style.next },
293
+ default: false,
294
+ pPr: {
295
+ ...style.pPr,
296
+ numPr: {
297
+ ...numPr,
298
+ numId: cloner.cloneNumId(numPr.numId)
299
+ }
300
+ }
301
+ };
302
+ clones.set(styleId, clone);
303
+ return cloneId;
304
+ };
305
+ return {
306
+ styleIdFor,
307
+ hasClones: () => clones.size > 0,
308
+ toDefinitions: (styles) => ({
309
+ ...styles,
310
+ styles: [...styles.styles, ...clones.values()]
311
+ })
312
+ };
313
+ };
314
+ const cloneParagraphForTarget = (paragraph, targetParaId, styleCloner, cloner) => {
315
+ const { textId: _textId, sectionProperties: _sectionProperties, ...rest } = paragraph;
316
+ const formatting = paragraph.formatting;
317
+ const nextFormatting = formatting && {
318
+ ...formatting,
319
+ ...formatting.styleId !== void 0 && { styleId: styleCloner.styleIdFor(formatting.styleId) },
320
+ ...formatting.numPr?.numId !== void 0 && formatting.numPr.numId !== 0 && { numPr: {
321
+ ...formatting.numPr,
322
+ numId: cloner.cloneNumId(formatting.numPr.numId)
323
+ } },
324
+ ...formatting.numPrFromStyle?.numId !== void 0 && formatting.numPrFromStyle.numId !== 0 && { numPrFromStyle: {
325
+ ...formatting.numPrFromStyle,
326
+ numId: cloner.cloneNumId(formatting.numPrFromStyle.numId)
327
+ } }
328
+ };
329
+ return {
330
+ ...rest,
331
+ content: structuredClone(paragraph.content),
332
+ paraId: targetParaId,
333
+ ...nextFormatting && { formatting: nextFormatting },
334
+ ...paragraph.listRendering && { listRendering: remapListRendering(paragraph.listRendering, cloner) }
335
+ };
336
+ };
337
+ const remapListRendering = (rendering, cloner) => {
338
+ const clonedAbstract = rendering.abstractNumId === void 0 ? void 0 : cloner.clonedAbstractNumId(rendering.abstractNumId);
339
+ return {
340
+ ...rendering,
341
+ numId: cloner.cloneNumId(rendering.numId),
342
+ ...clonedAbstract !== void 0 && { abstractNumId: clonedAbstract }
343
+ };
344
+ };
345
+ const collectTableParagraphs = (table) => {
346
+ const out = [];
347
+ for (const row of table.rows) for (const cell of row.cells) for (const item of cell.content) if (item.type === "paragraph") out.push(item);
348
+ else out.push(...collectTableParagraphs(item));
349
+ return out;
350
+ };
351
+ const buildRow = (left, right) => ({
352
+ type: "tableRow",
353
+ formatting: { cantSplit: true },
354
+ cells: [buildCell(left), buildCell(right)]
355
+ });
356
+ const buildCell = (paragraph) => ({
357
+ type: "tableCell",
358
+ formatting: {
359
+ width: {
360
+ value: HALF_WIDTH_PCT,
361
+ type: "pct"
362
+ },
363
+ verticalAlign: "top"
364
+ },
365
+ content: [paragraph]
366
+ });
367
+ /** A source table kept once, across both columns. */
368
+ const buildSpanningRow = (table) => ({
369
+ type: "tableRow",
370
+ formatting: { cantSplit: true },
371
+ cells: [{
372
+ type: "tableCell",
373
+ formatting: {
374
+ width: {
375
+ value: FULL_WIDTH_PCT,
376
+ type: "pct"
377
+ },
378
+ gridSpan: 2,
379
+ verticalAlign: "top"
380
+ },
381
+ content: [table, {
382
+ type: "paragraph",
383
+ content: []
384
+ }]
385
+ }]
386
+ });
387
+ const buildTable = (rows, borders, textWidth) => ({
388
+ type: "table",
389
+ formatting: {
390
+ width: {
391
+ value: FULL_WIDTH_PCT,
392
+ type: "pct"
393
+ },
394
+ layout: "fixed",
395
+ borders: TABLE_BORDERS[borders],
396
+ look: {
397
+ firstRow: false,
398
+ firstColumn: false,
399
+ noHBand: true,
400
+ noVBand: true
401
+ }
402
+ },
403
+ columnWidths: [Math.floor(textWidth / 2), Math.ceil(textWidth / 2)],
404
+ rows
405
+ });
406
+ const resolveTextWidthTwips = (doc) => {
407
+ const section = doc.package.document.finalSectionProperties ?? doc.package.document.sections?.at(0)?.properties;
408
+ if (!section?.pageWidth) return A4_TEXT_WIDTH_TWIPS;
409
+ const width = section.pageWidth - (section.marginLeft ?? 0) - (section.marginRight ?? 0);
410
+ return width > 0 ? width : A4_TEXT_WIDTH_TWIPS;
411
+ };
412
+ /**
413
+ * Every `paraId` anywhere in the package (body, headers, footers, notes,
414
+ * comments), so a minted id cannot collide with a part the body never sees.
415
+ * Walks the model generically: any object with `type: "paragraph"` and a
416
+ * string `paraId` counts.
417
+ */
418
+ const collectPackageParaIds = (pkg) => {
419
+ const ids = /* @__PURE__ */ new Set();
420
+ const seen = /* @__PURE__ */ new Set();
421
+ const visit = (value) => {
422
+ if (typeof value !== "object" || value === null || seen.has(value)) return;
423
+ seen.add(value);
424
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return;
425
+ if (Array.isArray(value)) {
426
+ for (const item of value) visit(item);
427
+ return;
428
+ }
429
+ if (value instanceof Map) {
430
+ for (const item of value.values()) visit(item);
431
+ return;
432
+ }
433
+ if (isParagraphWithId(value)) ids.add(value.paraId);
434
+ for (const child of Object.values(value)) visit(child);
435
+ };
436
+ visit(pkg);
437
+ return ids;
438
+ };
439
+ /**
440
+ * Fresh ids derived from the source id (so re-running on the same source
441
+ * yields the same handles), salted past any id already in the document.
442
+ */
443
+ const createParaIdMinter = (taken) => {
444
+ let ordinal = 0;
445
+ return { mint: (sourceParaId) => {
446
+ ordinal += 1;
447
+ const seed = `${ROW_ID_NAMESPACE}:${sourceParaId ?? `ordinal-${ordinal}`}`;
448
+ let id = deterministicHexId(seed);
449
+ for (let salt = 1; taken.has(id); salt += 1) id = deterministicHexId(`${seed}:${salt}`);
450
+ taken.add(id);
451
+ return id;
452
+ } };
453
+ };
454
+ /**
455
+ * Re-derive the row manifest from a document produced by
456
+ * {@link createBilingualDocument}. Detection is structural: a top-level table
457
+ * whose rows are all either a left | right pair of single-paragraph cells or
458
+ * one cell spanning both columns. Rows are returned in document order; the
459
+ * right paragraph's `paraId` is the row handle, as at creation.
460
+ */
461
+ function readBilingualDocument(document) {
462
+ const styleById = new Map((document.package.styles?.styles ?? []).map((style) => [style.styleId, style]));
463
+ const rows = [];
464
+ for (const block of flattenBlocks(document.package.document.content)) {
465
+ if (block.type !== "table" || !isBilingualTable(block)) continue;
466
+ for (const row of block.rows) {
467
+ const [left, right] = row.cells;
468
+ if (!left) continue;
469
+ if (!right) {
470
+ const paragraphs = left.content.filter((item) => item.type === "table").flatMap(collectTableParagraphs).map((paragraph) => ({
471
+ paraId: paragraph.paraId,
472
+ sourceText: getParagraphText(paragraph)
473
+ }));
474
+ rows.push({
475
+ kind: "table",
476
+ rowId: paragraphs.at(0)?.paraId ?? tableRowHandle(rows.length),
477
+ paragraphs
478
+ });
479
+ continue;
480
+ }
481
+ const source = left.content.at(0);
482
+ const target = right.content.at(0);
483
+ if (source?.type !== "paragraph" || target?.type !== "paragraph" || !target.paraId) continue;
484
+ rows.push({
485
+ kind: classifyParagraph(source, styleById),
486
+ rowId: target.paraId,
487
+ sourceParaId: source.paraId,
488
+ targetParaId: target.paraId,
489
+ sourceText: getParagraphText(source)
490
+ });
491
+ }
492
+ }
493
+ return rows;
494
+ }
495
+ const isBilingualTable = (table) => {
496
+ let pairs = 0;
497
+ for (const row of table.rows) {
498
+ const cells = row.cells;
499
+ if (cells.length === 2) {
500
+ if (!cells.every((cell) => cell.content.length === 1 && cell.content[0]?.type === "paragraph")) return false;
501
+ pairs += 1;
502
+ continue;
503
+ }
504
+ if (cells.length === 1 && cells[0]?.formatting?.gridSpan === 2) continue;
505
+ return false;
506
+ }
507
+ return pairs > 0;
508
+ };
509
+ const isParagraphWithId = (value) => "type" in value && value.type === "paragraph" && "paraId" in value && typeof value.paraId === "string";
510
+ //#endregion
511
+ export { InvalidBilingualDocumentOptionsError, createBilingualDocument, readBilingualDocument };
@@ -0,0 +1,19 @@
1
+ import { BilingualRow, CreateBilingualDocumentOptions } from "./createBilingualDocument.js";
2
+ //#region src/docx/server/createBilingualDocx.d.ts
3
+ type CreateBilingualDocxResult = {
4
+ buffer: ArrayBuffer;
5
+ rows: BilingualRow[];
6
+ warnings: string[];
7
+ };
8
+ /**
9
+ * Bytes-in / bytes-out form of {@link createBilingualDocument}: stamp every
10
+ * paragraph with a `paraId` (so left-column rows are addressable later), parse
11
+ * the DOCX (no font preloading, so it never touches the DOM), lay the body out
12
+ * as a two-column table, and repack onto the original package so theme, fonts,
13
+ * media, headers and footers carry over untouched.
14
+ */
15
+ declare function createBilingualDocx(input: ArrayBuffer | Uint8Array, options: CreateBilingualDocumentOptions): Promise<CreateBilingualDocxResult>;
16
+ /** Bytes-in form of {@link readBilingualDocument}. */
17
+ declare function readBilingualDocx(input: ArrayBuffer | Uint8Array): Promise<BilingualRow[]>;
18
+ //#endregion
19
+ export { CreateBilingualDocxResult, createBilingualDocx, readBilingualDocx };
@@ -0,0 +1,26 @@
1
+ import { ensureParaIds } from "../ensureParaIds.js";
2
+ import { parseDocx } from "../parser.js";
3
+ import { createDocx } from "../rezip.js";
4
+ import { createBilingualDocument, readBilingualDocument } from "./createBilingualDocument.js";
5
+ //#region src/docx/server/createBilingualDocx.ts
6
+ /**
7
+ * Bytes-in / bytes-out form of {@link createBilingualDocument}: stamp every
8
+ * paragraph with a `paraId` (so left-column rows are addressable later), parse
9
+ * the DOCX (no font preloading, so it never touches the DOM), lay the body out
10
+ * as a two-column table, and repack onto the original package so theme, fonts,
11
+ * media, headers and footers carry over untouched.
12
+ */
13
+ async function createBilingualDocx(input, options) {
14
+ const { document, rows, warnings } = createBilingualDocument(await parseDocx((await ensureParaIds(input)).docx, { preloadFonts: false }), options);
15
+ return {
16
+ buffer: await createDocx(document),
17
+ rows,
18
+ warnings
19
+ };
20
+ }
21
+ /** Bytes-in form of {@link readBilingualDocument}. */
22
+ async function readBilingualDocx(input) {
23
+ return readBilingualDocument(await parseDocx(input, { preloadFonts: false }));
24
+ }
25
+ //#endregion
26
+ export { createBilingualDocx, readBilingualDocx };
package/dist/server.d.ts CHANGED
@@ -19,9 +19,11 @@ import { EvaluateDocxXmlPatchProposalArgs, FOLIO_DOCX_XML_PATCH_PROPOSAL_DEFAULT
19
19
  import { FOLIO_DOCX_CONFORMANCE_CHECKS, FOLIO_DOCX_CONFORMANCE_ISSUE_CODES, FOLIO_DOCX_CONFORMANCE_PROFILE, FOLIO_DOCX_CONFORMANCE_REPORT_VERSION, FolioDocxConformanceCheck, FolioDocxConformanceCheckId, FolioDocxConformanceCheckStatus, FolioDocxConformanceIssue, FolioDocxConformanceIssueCode, FolioDocxConformanceReport, FolioDocxConformanceStatus, ValidateDocxConformanceOptions, validateDocxConformance } from "./docx/server/validateDocxConformance.js";
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
+ 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";
22
24
  import { docxToMarkdown } from "./docx/server/docxToMarkdown.js";
23
25
  import { DocxParagraphSource, DocxTableRowKind, DocxTableRowPosition, ExtractedDocxParagraph, ExtractedDocxTableCell, ExtractedDocxTableCellParagraph, ExtractedDocxText, extractDocxText } from "./docx/server/extractDocxText.js";
24
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";
25
27
  import { GenerateRedlineDocxOptions, GenerateRedlineDocxResult, GenerateRedlineUnprocessedStory, InvalidGenerateRedlineDocxOptionsError, generateRedlineDocx } from "./redline.js";
26
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";
27
- export { type ApplyDocxXmlPatchProposalArgs, type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, 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, 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, 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, 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 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/server.js CHANGED
@@ -10,6 +10,8 @@ import { createDocx } from "./docx/rezip.js";
10
10
  import { FOLIO_DOCX_XML_PATCH_APPLICATION_PROFILE, FOLIO_DOCX_XML_PATCH_APPLICATION_VERSION, FolioDocxXmlPatchApplicationError, UnsupportedFolioDocxXmlPatchApplicationProfileError, applyDocxXmlPatchProposal } from "./docx/server/applyDocxXmlPatchProposal.js";
11
11
  import { DocxArchiveError } from "./docx/server/boundedArchive.js";
12
12
  import { HEADING_LEVELS, InvalidFolioReportBuilderOptionsError, bookmark, createTableOfContentsField, endnote, heading, hyperlink, pageBreak, paragraph, run, table } from "./docx/server/build.js";
13
+ import { InvalidBilingualDocumentOptionsError, createBilingualDocument, readBilingualDocument } from "./docx/server/createBilingualDocument.js";
14
+ import { createBilingualDocx, readBilingualDocx } from "./docx/server/createBilingualDocx.js";
13
15
  import { docxToMarkdown } from "./docx/server/docxToMarkdown.js";
14
16
  import { 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, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, evaluateDocxXmlPatchProposal, parseFolioDocxXmlPatchProposal } from "./docx/server/evaluateDocxXmlPatchProposal.js";
15
17
  import { extractDocxText } from "./docx/server/extractDocxText.js";
@@ -22,4 +24,4 @@ import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION } from "./style-set
22
24
  import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
23
25
  import { createEmptyDocument } from "./utils/createDocument.js";
24
26
  import { FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS, FOLIO_VERSION_COMPARISON_SCOPES, InvalidFolioVersionComparisonOptionsError, applyFolioVersionDiffPrivacy, compareDocxVersions, isFolioVersionComparisonPrivacyTransform, isFolioVersionComparisonScope } from "./version-comparison.js";
25
- export { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocxArchiveError, EnsureParaIdsError, 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, FolioDocumentPrivacyArchiveError, FolioDocumentStoryNotFoundError, FolioDocxPackageInspectionError, FolioDocxReviewer, FolioDocxXmlPatchApplicationError, HEADING_LEVELS, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, InvalidFolioReportBuilderOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioDocxXmlPatchApplicationProfileError, UnsupportedFolioReviewedViewError, applyDocxXmlPatchProposal, applyFolioAIEditsToBuffer, applyFolioVersionDiffPrivacy, assertSupportedFolioDocumentOperationVersion, bookmark, compareDocxVersions, 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, readFolioDocumentSection, replyToComment, rewriteDocxMetadataPrivacy, run, table, validateDocxConformance };
27
+ export { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocxArchiveError, EnsureParaIdsError, 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, FolioDocumentPrivacyArchiveError, FolioDocumentStoryNotFoundError, FolioDocxPackageInspectionError, FolioDocxReviewer, FolioDocxXmlPatchApplicationError, HEADING_LEVELS, InvalidBilingualDocumentOptionsError, InvalidFolioDocumentOperationBatchError, InvalidFolioDocumentPrivacyOptionsError, InvalidFolioDocxXmlPatchProposalError, InvalidFolioDocxXmlPatchProposalOptionsError, InvalidFolioReportBuilderOptionsError, InvalidFolioVersionComparisonOptionsError, InvalidGenerateRedlineDocxOptionsError, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioDocxXmlPatchApplicationProfileError, UnsupportedFolioReviewedViewError, 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.21.0",
3
+ "version": "0.22.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",