@stll/folio-core 0.35.0 → 0.36.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/ai-edits/apply.js +370 -118
- package/dist/ai-edits/headless.js +16 -10
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/snapshot.js +6 -1
- package/dist/ai-edits/types.d.ts +19 -6
- package/dist/ai-edits/word-diff.d.ts +18 -3
- package/dist/ai-edits/word-diff.js +556 -67
- package/dist/compare/compare.js +7 -16
- package/dist/compare/plan.js +8 -5
- package/dist/compare/verification.d.ts +8 -9
- package/dist/compare/verification.js +51 -46
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/compat/eigenpal.js +2 -2
- package/dist/controller/headerFooterEditorManager.js +5 -5
- package/dist/controller/hiddenEditorApi.js +1 -1
- package/dist/controller/noteEditorManager.js +2 -2
- package/dist/document-operations.d.ts +5 -3
- package/dist/document-operations.js +32 -5
- package/dist/docx/commentParser.js +2 -4
- package/dist/docx/commentRangeIntegrity.js +2 -4
- package/dist/docx/documentClone.d.ts +2 -0
- package/dist/docx/documentClone.js +2 -0
- package/dist/docx/headerFooterParser.js +2 -4
- package/dist/docx/normalizeBaseDirection.js +5 -7
- package/dist/docx/paragraphParser.js +27 -29
- package/dist/docx/paragraphPropertySource.d.ts +49 -0
- package/dist/docx/paragraphPropertySource.js +113 -0
- package/dist/docx/runConsolidator.js +3 -4
- package/dist/docx/runParser.js +2 -15
- package/dist/docx/sectionParser.js +1 -15
- package/dist/docx/serializer/paragraphSerializer.js +287 -30
- package/dist/docx/serializer/runSerializer.js +2 -10
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
- package/dist/docx/serializer/tableSerializer.js +4 -23
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +9 -0
- package/dist/docx/serializer/trackedChangeAttributes.js +21 -0
- package/dist/docx/server/createBilingualDocument.js +8 -10
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
- package/dist/docx/server/validateDocxConformance.js +17 -13
- package/dist/docx/tableParser.js +1 -37
- package/dist/docx/trackedChangeInfo.d.ts +11 -0
- package/dist/docx/trackedChangeInfo.js +38 -0
- package/dist/docx/verbatimCapture.d.ts +20 -9
- package/dist/docx/verbatimCapture.js +208 -8
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +6 -1
- package/dist/docx/xmlSafety.d.ts +1 -1
- package/dist/docx/xmlSafety.js +157 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/layout-bridge/convert/headerFooterLayout.js +4 -4
- package/dist/layout-bridge/convert/toFlowBlocks.js +12 -7
- package/dist/markdown/renderBlock.js +7 -10
- package/dist/prosemirror/attrs/index.js +15 -0
- package/dist/prosemirror/commands/comments.js +365 -32
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +26 -4
- package/dist/prosemirror/commands/propertyChangeScope.js +65 -3
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -4
- package/dist/prosemirror/conversion/fromProseDoc.js +130 -18
- package/dist/prosemirror/conversion/toProseDoc.js +27 -12
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +48 -4
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +20 -7
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/paragraphAlignment.d.ts +12 -0
- package/dist/prosemirror/paragraphAlignment.js +13 -0
- package/dist/prosemirror/plugins/suggestionMode.js +1 -1
- package/dist/prosemirror/schema/marks.d.ts +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +12 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/redline.js +4 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/utils/mergeDocumentContent.js +3 -3
- package/dist/utils/replaceText.js +2 -1
- package/dist/version-comparison.js +6 -4
- package/dist/watermark/index.js +2 -4
- package/package.json +7 -2
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
1
2
|
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
2
3
|
import { numPrEqual } from "../numberingParser.js";
|
|
4
|
+
import { getParagraphPropertySource } from "../paragraphPropertySource.js";
|
|
3
5
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
6
|
+
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
7
|
+
import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
|
|
8
|
+
import { captureVerbatimXml, sanitizeCapturedXmlElement } from "../verbatimCapture.js";
|
|
9
|
+
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
4
10
|
import { serializeBorder } from "./borderSerializer.js";
|
|
5
11
|
import { serializeRun, serializeTextFormatting } from "./runSerializer.js";
|
|
6
12
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
13
|
+
import { serializeTrackedChangeAttributes, trackedChangeAttributeRecord } from "./trackedChangeAttributes.js";
|
|
7
14
|
import { escapeXml, intAttr, isSingleWellFormedElement } from "./xmlUtils.js";
|
|
8
|
-
import {
|
|
15
|
+
import { panic } from "better-result";
|
|
16
|
+
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
9
17
|
//#region src/docx/serializer/paragraphSerializer.ts
|
|
10
18
|
/**
|
|
11
19
|
* Serialize paragraph borders (w:pBdr)
|
|
@@ -131,16 +139,278 @@ function serializeFrameProperties(frame) {
|
|
|
131
139
|
/**
|
|
132
140
|
* Serialize paragraph formatting properties to w:pPr XML
|
|
133
141
|
*/
|
|
134
|
-
function serializeTrackedChangeAttrs(info) {
|
|
135
|
-
const parts = [`w:id="${normalizeRevisionId(info.id)}"`, `w:author="${escapeXml(info.author)}"`];
|
|
136
|
-
if (info.date !== void 0) parts.push(`w:date="${escapeXml(info.date)}"`);
|
|
137
|
-
return parts.join(" ");
|
|
138
|
-
}
|
|
139
142
|
function serializeParagraphMarkChange(mark) {
|
|
140
|
-
const attrs =
|
|
143
|
+
const attrs = serializeTrackedChangeAttributes(mark.info);
|
|
141
144
|
return `<w:${mark.kind} ${attrs}/>`;
|
|
142
145
|
}
|
|
143
|
-
const
|
|
146
|
+
const RESERVED_PARAGRAPH_PROPERTY_CHILDREN = /* @__PURE__ */ new Set(["pPrChange", "sectPr"]);
|
|
147
|
+
const RESERVED_PARAGRAPH_CAPTURE_CHILDREN = /* @__PURE__ */ new Set([
|
|
148
|
+
...RESERVED_PARAGRAPH_PROPERTY_CHILDREN,
|
|
149
|
+
...PARAGRAPH_MARK_CHANGE_KINDS,
|
|
150
|
+
"cellDel",
|
|
151
|
+
"cellIns",
|
|
152
|
+
"cellMerge",
|
|
153
|
+
"numberingChange",
|
|
154
|
+
"rPrChange",
|
|
155
|
+
"tblGridChange",
|
|
156
|
+
"tblPrChange",
|
|
157
|
+
"tcPrChange",
|
|
158
|
+
"trPrChange"
|
|
159
|
+
]);
|
|
160
|
+
const PARAGRAPH_PROPERTY_ROOT_NAME = /* @__PURE__ */ new Set(["pPr"]);
|
|
161
|
+
const WORDPROCESSINGML_NAMESPACE = /* @__PURE__ */ new Set([NAMESPACES.w]);
|
|
162
|
+
const PARAGRAPH_APPEND_PREFIXES = /* @__PURE__ */ new Map([
|
|
163
|
+
["w", NAMESPACES.w],
|
|
164
|
+
["r", NAMESPACES.r],
|
|
165
|
+
["w15", NAMESPACES.w15]
|
|
166
|
+
]);
|
|
167
|
+
const PARAGRAPH_PROPERTY_CHILD_ORDER = new Map([
|
|
168
|
+
"pStyle",
|
|
169
|
+
"keepNext",
|
|
170
|
+
"keepLines",
|
|
171
|
+
"pageBreakBefore",
|
|
172
|
+
"framePr",
|
|
173
|
+
"widowControl",
|
|
174
|
+
"numPr",
|
|
175
|
+
"suppressLineNumbers",
|
|
176
|
+
"pBdr",
|
|
177
|
+
"shd",
|
|
178
|
+
"tabs",
|
|
179
|
+
"suppressAutoHyphens",
|
|
180
|
+
"kinsoku",
|
|
181
|
+
"wordWrap",
|
|
182
|
+
"overflowPunct",
|
|
183
|
+
"topLinePunct",
|
|
184
|
+
"autoSpaceDE",
|
|
185
|
+
"autoSpaceDN",
|
|
186
|
+
"bidi",
|
|
187
|
+
"adjustRightInd",
|
|
188
|
+
"snapToGrid",
|
|
189
|
+
"spacing",
|
|
190
|
+
"ind",
|
|
191
|
+
"contextualSpacing",
|
|
192
|
+
"mirrorIndents",
|
|
193
|
+
"suppressOverlap",
|
|
194
|
+
"jc",
|
|
195
|
+
"textDirection",
|
|
196
|
+
"textAlignment",
|
|
197
|
+
"textboxTightWrap",
|
|
198
|
+
"outlineLvl",
|
|
199
|
+
"divId",
|
|
200
|
+
"cnfStyle",
|
|
201
|
+
"rPr"
|
|
202
|
+
].map((name, index) => [name, index]));
|
|
203
|
+
const PARAGRAPH_MARK_BASE_CHILDREN = /* @__PURE__ */ new Set([
|
|
204
|
+
"rStyle",
|
|
205
|
+
"rFonts",
|
|
206
|
+
"b",
|
|
207
|
+
"bCs",
|
|
208
|
+
"i",
|
|
209
|
+
"iCs",
|
|
210
|
+
"caps",
|
|
211
|
+
"smallCaps",
|
|
212
|
+
"strike",
|
|
213
|
+
"dstrike",
|
|
214
|
+
"outline",
|
|
215
|
+
"shadow",
|
|
216
|
+
"emboss",
|
|
217
|
+
"imprint",
|
|
218
|
+
"snapToGrid",
|
|
219
|
+
"vanish",
|
|
220
|
+
"webHidden",
|
|
221
|
+
"color",
|
|
222
|
+
"spacing",
|
|
223
|
+
"w",
|
|
224
|
+
"kern",
|
|
225
|
+
"position",
|
|
226
|
+
"sz",
|
|
227
|
+
"szCs",
|
|
228
|
+
"noProof",
|
|
229
|
+
"highlight",
|
|
230
|
+
"u",
|
|
231
|
+
"effect",
|
|
232
|
+
"bdr",
|
|
233
|
+
"shd",
|
|
234
|
+
"fitText",
|
|
235
|
+
"vertAlign",
|
|
236
|
+
"rtl",
|
|
237
|
+
"cs",
|
|
238
|
+
"em",
|
|
239
|
+
"lang",
|
|
240
|
+
"eastAsianLayout",
|
|
241
|
+
"specVanish",
|
|
242
|
+
"oMath"
|
|
243
|
+
]);
|
|
244
|
+
const PARAGRAPH_NESTED_PROPERTY_CHILDREN = /* @__PURE__ */ new Map([
|
|
245
|
+
["numPr", /* @__PURE__ */ new Set(["ilvl", "numId"])],
|
|
246
|
+
["pBdr", /* @__PURE__ */ new Set([
|
|
247
|
+
"top",
|
|
248
|
+
"left",
|
|
249
|
+
"bottom",
|
|
250
|
+
"right",
|
|
251
|
+
"between",
|
|
252
|
+
"bar"
|
|
253
|
+
])],
|
|
254
|
+
["tabs", /* @__PURE__ */ new Set(["tab"])],
|
|
255
|
+
["rPr", PARAGRAPH_MARK_BASE_CHILDREN]
|
|
256
|
+
]);
|
|
257
|
+
const resolveNamespaceBinding = (scope, prefix) => {
|
|
258
|
+
for (let current = scope; current; current = current.parent) {
|
|
259
|
+
const value = current.bindings.get(prefix);
|
|
260
|
+
if (value !== void 0) return value;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const hasDescendantNamed = (element, namespaceUri, localName) => {
|
|
264
|
+
const pending = [...getChildElements(element)];
|
|
265
|
+
while (pending.length > 0) {
|
|
266
|
+
const child = pending.pop();
|
|
267
|
+
if (!child) continue;
|
|
268
|
+
if (getLocalName(child.name) === localName && toTransitionalNamespaceUri(child.namespaceUri ?? "") === namespaceUri) return true;
|
|
269
|
+
for (const descendant of getChildElements(child)) pending.push(descendant);
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
};
|
|
273
|
+
const hasInvalidParagraphPropertyRevision = (root) => {
|
|
274
|
+
const pending = [...getChildElements(root)];
|
|
275
|
+
while (pending.length > 0) {
|
|
276
|
+
const element = pending.pop();
|
|
277
|
+
if (!element) continue;
|
|
278
|
+
if (toTransitionalNamespaceUri(element.namespaceUri ?? "") === NAMESPACES.w) {
|
|
279
|
+
const localName = getLocalName(element.name);
|
|
280
|
+
if (RESERVED_PARAGRAPH_CAPTURE_CHILDREN.has(localName)) return true;
|
|
281
|
+
}
|
|
282
|
+
for (const child of getChildElements(element)) pending.push(child);
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
};
|
|
286
|
+
const hasInvalidParagraphPropertyShape = (root) => {
|
|
287
|
+
const pending = getChildElements(root).map((element) => ({
|
|
288
|
+
element,
|
|
289
|
+
parent: root
|
|
290
|
+
}));
|
|
291
|
+
if ((root.elements ?? []).some((child) => child.type === "text" && String(child.text ?? "").trim() !== "")) return true;
|
|
292
|
+
while (pending.length > 0) {
|
|
293
|
+
const entry = pending.pop();
|
|
294
|
+
if (!entry) continue;
|
|
295
|
+
const { element, parent } = entry;
|
|
296
|
+
if ((element.elements ?? []).some((child) => child.type === "text" && String(child.text ?? "").trim() !== "")) return true;
|
|
297
|
+
if (toTransitionalNamespaceUri(element.namespaceUri ?? "") === NAMESPACES.w && parent !== root) {
|
|
298
|
+
if (toTransitionalNamespaceUri(parent.namespaceUri ?? "") !== NAMESPACES.w) return true;
|
|
299
|
+
if (!PARAGRAPH_NESTED_PROPERTY_CHILDREN.get(getLocalName(parent.name))?.has(getLocalName(element.name))) return true;
|
|
300
|
+
}
|
|
301
|
+
for (const child of getChildElements(element)) pending.push({
|
|
302
|
+
element: child,
|
|
303
|
+
parent: element
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
};
|
|
308
|
+
const sourceShadowsDateUtcPrefix = (sourceXml) => {
|
|
309
|
+
const root = parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
|
|
310
|
+
if (!root || root.type !== "element") return true;
|
|
311
|
+
const pending = [root];
|
|
312
|
+
while (pending.length > 0) {
|
|
313
|
+
const element = pending.pop();
|
|
314
|
+
if (!element) continue;
|
|
315
|
+
const resolved = resolveNamespaceBinding(element.namespaceScope, "w16du");
|
|
316
|
+
if (resolved !== void 0 && resolved !== "http://schemas.microsoft.com/office/word/2023/wordml/word16du") return true;
|
|
317
|
+
for (const child of getChildElements(element)) pending.push(child);
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
};
|
|
321
|
+
const hasInvalidParagraphMarkProperties = (root) => {
|
|
322
|
+
for (const child of getChildElements(root)) {
|
|
323
|
+
if (toTransitionalNamespaceUri(child.namespaceUri ?? "") !== NAMESPACES.w) continue;
|
|
324
|
+
const localName = getLocalName(child.name);
|
|
325
|
+
if (!PARAGRAPH_MARK_BASE_CHILDREN.has(localName)) return true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
};
|
|
329
|
+
const replayableParagraphPropertySourceXml = (sourceXml) => {
|
|
330
|
+
return sanitizeCapturedXmlElement(sourceXml, {
|
|
331
|
+
allowedLocalNames: PARAGRAPH_PROPERTY_ROOT_NAME,
|
|
332
|
+
allowedNamespaceUris: WORDPROCESSINGML_NAMESPACE,
|
|
333
|
+
inheritedNamespaceScope: OOXML_NAMESPACE_SCOPE,
|
|
334
|
+
requiredNamespaceBindings: PARAGRAPH_APPEND_PREFIXES,
|
|
335
|
+
validate: (root) => {
|
|
336
|
+
let paragraphMarkProperties = null;
|
|
337
|
+
const seenChildren = /* @__PURE__ */ new Set();
|
|
338
|
+
let previousChildOrder = -1;
|
|
339
|
+
for (const child of getChildElements(root)) {
|
|
340
|
+
const localName = getLocalName(child.name);
|
|
341
|
+
const isWordprocessingChild = toTransitionalNamespaceUri(child.namespaceUri ?? "") === NAMESPACES.w;
|
|
342
|
+
if (isWordprocessingChild) {
|
|
343
|
+
if (RESERVED_PARAGRAPH_PROPERTY_CHILDREN.has(localName)) return false;
|
|
344
|
+
const childOrder = PARAGRAPH_PROPERTY_CHILD_ORDER.get(localName);
|
|
345
|
+
if (childOrder === void 0 || seenChildren.has(localName) || childOrder < previousChildOrder) return false;
|
|
346
|
+
seenChildren.add(localName);
|
|
347
|
+
previousChildOrder = childOrder;
|
|
348
|
+
}
|
|
349
|
+
if (localName !== "rPr" || !isWordprocessingChild) {
|
|
350
|
+
if (hasDescendantNamed(child, NAMESPACES.w, "rPr")) return false;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (paragraphMarkProperties !== null || toTransitionalNamespaceUri(resolveNamespaceBinding(child.namespaceScope, "w") ?? "") !== NAMESPACES.w) return false;
|
|
354
|
+
paragraphMarkProperties = child;
|
|
355
|
+
}
|
|
356
|
+
return !(paragraphMarkProperties && hasInvalidParagraphMarkProperties(paragraphMarkProperties) || hasInvalidParagraphPropertyShape(root) || hasInvalidParagraphPropertyRevision(root));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
const verifiedParagraphPropertySource = (formatting, source) => {
|
|
361
|
+
if (!source) return null;
|
|
362
|
+
const replayableSource = replayableParagraphPropertySourceXml(source.xml);
|
|
363
|
+
if (replayableSource === null) return null;
|
|
364
|
+
return canonicalJson(formatting ?? {}) === source.formattingJson ? replayableSource : null;
|
|
365
|
+
};
|
|
366
|
+
const withTrailingParagraphPropertyChildren = (sourceXml, children) => {
|
|
367
|
+
const written = children.join("");
|
|
368
|
+
if (written.length === 0) return sourceXml;
|
|
369
|
+
const selfClosing = /^<((?:[A-Za-z_][\w.-]*:)?pPr)\b([^>]*)\/>$/u.exec(sourceXml);
|
|
370
|
+
if (selfClosing) {
|
|
371
|
+
const [, name, attrs] = selfClosing;
|
|
372
|
+
return `<${name}${attrs}>${written}</${name}>`;
|
|
373
|
+
}
|
|
374
|
+
const close = sourceXml.lastIndexOf("</");
|
|
375
|
+
return close === -1 ? sourceXml : `${sourceXml.slice(0, close)}${written}${sourceXml.slice(close)}`;
|
|
376
|
+
};
|
|
377
|
+
const withParagraphMarkChange = (sourceXml, mark) => {
|
|
378
|
+
const root = parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
|
|
379
|
+
if (!root || root.type !== "element") panic("A validated paragraph-property capture could not be parsed for composition");
|
|
380
|
+
const attributes = trackedChangeAttributeRecord(mark.info);
|
|
381
|
+
const markElement = cloneElement(root, {
|
|
382
|
+
name: `w:${mark.kind}`,
|
|
383
|
+
attributes,
|
|
384
|
+
elements: []
|
|
385
|
+
});
|
|
386
|
+
const elements = [...root.elements ?? []];
|
|
387
|
+
const paragraphMarkIndex = elements.findIndex((child) => child.type === "element" && getLocalName(child.name) === "rPr" && toTransitionalNamespaceUri(child.namespaceUri ?? "") === NAMESPACES.w);
|
|
388
|
+
if (paragraphMarkIndex === -1) elements.push(cloneElement(root, {
|
|
389
|
+
name: "w:rPr",
|
|
390
|
+
attributes: {},
|
|
391
|
+
elements: [markElement]
|
|
392
|
+
}));
|
|
393
|
+
else {
|
|
394
|
+
const paragraphMarkProperties = elements[paragraphMarkIndex];
|
|
395
|
+
if (!paragraphMarkProperties || paragraphMarkProperties.type !== "element") panic("A validated paragraph-mark property node disappeared during composition");
|
|
396
|
+
elements[paragraphMarkIndex] = cloneElement(paragraphMarkProperties, { elements: [markElement, ...paragraphMarkProperties.elements ?? []] });
|
|
397
|
+
}
|
|
398
|
+
return captureVerbatimXml(cloneElement(root, { elements }));
|
|
399
|
+
};
|
|
400
|
+
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sectionProperties } = {}) => {
|
|
401
|
+
const paragraphMarkXml = paragraphMarkChange ? serializeParagraphMarkChange(paragraphMarkChange) : "";
|
|
402
|
+
const sectionPropertiesXml = serializeSectionProperties(sectionProperties);
|
|
403
|
+
const propertyChangesXml = (propertyChanges ?? []).map((change) => serializeParagraphPropertyChange(change));
|
|
404
|
+
const composedChildrenUseDateUtc = [
|
|
405
|
+
paragraphMarkXml,
|
|
406
|
+
sectionPropertiesXml,
|
|
407
|
+
...propertyChangesXml
|
|
408
|
+
].some((xml) => xml.includes(`${DATE_UTC_ATTRIBUTE}=`));
|
|
409
|
+
const verifiedSource = verifiedParagraphPropertySource(formatting, propertySource);
|
|
410
|
+
if (verifiedSource !== null && (!composedChildrenUseDateUtc || !sourceShadowsDateUtcPrefix(verifiedSource))) {
|
|
411
|
+
const sourceWithMark = paragraphMarkChange ? withParagraphMarkChange(verifiedSource, paragraphMarkChange) : verifiedSource;
|
|
412
|
+
return withTrailingParagraphPropertyChildren(sourceWithMark, [sectionPropertiesXml, ...propertyChangesXml]);
|
|
413
|
+
}
|
|
144
414
|
const parts = [];
|
|
145
415
|
const pushToggle = (name, value) => {
|
|
146
416
|
if (value === true) parts.push(`<w:${name}/>`);
|
|
@@ -156,13 +426,13 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
156
426
|
pushToggle("widowControl", formatting.widowControl);
|
|
157
427
|
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
158
428
|
if (numPrXml) parts.push(numPrXml);
|
|
429
|
+
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
159
430
|
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
160
431
|
if (bordersXml) parts.push(bordersXml);
|
|
161
432
|
const shadingXml = serializeShading(formatting.shading);
|
|
162
433
|
if (shadingXml) parts.push(shadingXml);
|
|
163
434
|
const tabsXml = serializeTabStops(formatting.tabs);
|
|
164
435
|
if (tabsXml) parts.push(tabsXml);
|
|
165
|
-
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
166
436
|
pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
|
|
167
437
|
pushToggle("kinsoku", formatting.kinsoku);
|
|
168
438
|
pushToggle("overflowPunct", formatting.overflowPunctuation);
|
|
@@ -176,12 +446,12 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
176
446
|
if (formatting.alignment) parts.push(`<w:jc w:val="${formatting.alignment}"/>`);
|
|
177
447
|
if (formatting.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${formatting.outlineLevel}"/>`);
|
|
178
448
|
if (paragraphMarkChange || formatting.runProperties || formatting.runInWithNext) {
|
|
179
|
-
const fullInner = `${paragraphMarkChange ?
|
|
449
|
+
const fullInner = `${paragraphMarkChange ? paragraphMarkXml : ""}${formatting.runProperties ? extractRPrInner(serializeTextFormatting(formatting.runProperties)) : ""}${formatting.runInWithNext ? "<w:specVanish/>" : ""}`;
|
|
180
450
|
if (fullInner.length > 0) parts.push(`<w:rPr>${fullInner}</w:rPr>`);
|
|
181
451
|
}
|
|
182
|
-
} else if (paragraphMarkChange) parts.push(`<w:rPr>${
|
|
183
|
-
parts.push(
|
|
184
|
-
if (
|
|
452
|
+
} else if (paragraphMarkChange) parts.push(`<w:rPr>${paragraphMarkXml}</w:rPr>`);
|
|
453
|
+
parts.push(sectionPropertiesXml);
|
|
454
|
+
if (propertyChangesXml.length > 0) parts.push(...propertyChangesXml);
|
|
185
455
|
const inner = parts.join("");
|
|
186
456
|
if (inner.length === 0) return "";
|
|
187
457
|
return `<w:pPr>${inner}</w:pPr>`;
|
|
@@ -206,17 +476,9 @@ function extractRPrInner(rPrXml) {
|
|
|
206
476
|
return rPrXml.slice(7, -8);
|
|
207
477
|
}
|
|
208
478
|
function serializeParagraphPropertyChange(change) {
|
|
209
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
210
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
211
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
212
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
213
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
214
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
215
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
216
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
217
479
|
const previousPPrInner = extractPPrInner(serializeParagraphFormatting(change.previousFormatting) || "<w:pPr/>");
|
|
218
480
|
const normalizedPreviousPPr = previousPPrInner.length > 0 ? `<w:pPr>${previousPPrInner}</w:pPr>` : "<w:pPr/>";
|
|
219
|
-
return `<w:pPrChange ${
|
|
481
|
+
return `<w:pPrChange ${serializeTrackedChangeAttributes(change.info)}>${normalizedPreviousPPr}</w:pPrChange>`;
|
|
220
482
|
}
|
|
221
483
|
/** The attribute list of a `w:hyperlink`, without its children. */
|
|
222
484
|
function hyperlinkAttributes(hyperlink) {
|
|
@@ -390,13 +652,7 @@ function trackedChangeTag(change) {
|
|
|
390
652
|
}
|
|
391
653
|
}
|
|
392
654
|
function serializeTrackedChange(tag, change) {
|
|
393
|
-
const
|
|
394
|
-
const normalizedId = normalizeRevisionId(info.id);
|
|
395
|
-
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
396
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
397
|
-
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
398
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
399
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
655
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
400
656
|
const serializeDeletedRun = (run) => {
|
|
401
657
|
const xml = serializeRun(run);
|
|
402
658
|
if (!run.content.some((c) => c.type === "drawing" || c.type === "shape")) return rewriteRunTextAsDeleted(xml);
|
|
@@ -420,7 +676,7 @@ function serializeTrackedChange(tag, change) {
|
|
|
420
676
|
if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return serializeTrackedChange(trackedChangeTag(item), item);
|
|
421
677
|
return item.type === "bookmarkStart" ? serializeBookmarkStart(item) : serializeBookmarkEnd(item);
|
|
422
678
|
};
|
|
423
|
-
const open = `<w:${tag} ${attrs
|
|
679
|
+
const open = `<w:${tag} ${attrs}>`;
|
|
424
680
|
const close = `</w:${tag}>`;
|
|
425
681
|
const wrap = (inner) => inner.length === 0 ? "" : `${open}${inner}${close}`;
|
|
426
682
|
if (change.content.length === 0) return `${open}${close}`;
|
|
@@ -497,6 +753,7 @@ function serializeParagraph(paragraph) {
|
|
|
497
753
|
parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
|
|
498
754
|
propertyChanges: paragraph.propertyChanges,
|
|
499
755
|
paragraphMarkChange: paragraph.pPrMark,
|
|
756
|
+
propertySource: getParagraphPropertySource(paragraph),
|
|
500
757
|
sectionProperties: paragraph.sectionProperties
|
|
501
758
|
}));
|
|
502
759
|
const explicitCommentReferenceIds = /* @__PURE__ */ new Set();
|
|
@@ -5,9 +5,9 @@ import { THEME_COLOR_TO_DRAWING_SCHEME } from "../drawingUtils.js";
|
|
|
5
5
|
import { requiresXmlSpacePreserve } from "../textWhitespace.js";
|
|
6
6
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
7
7
|
import { serializeTable } from "./tableSerializer.js";
|
|
8
|
+
import { serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
8
9
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
9
10
|
import { panic } from "better-result";
|
|
10
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
11
11
|
//#region src/docx/serializer/runSerializer.ts
|
|
12
12
|
/**
|
|
13
13
|
* Run Serializer - Serialize runs to OOXML XML
|
|
@@ -169,16 +169,8 @@ function extractRPrInner(rPrXml) {
|
|
|
169
169
|
return rPrXml.slice(7, -8);
|
|
170
170
|
}
|
|
171
171
|
function serializeRunPropertyChange(change) {
|
|
172
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
173
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
174
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
175
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
176
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
177
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
178
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
179
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
180
172
|
const previousRPrXml = serializeTextFormatting(change.previousFormatting) || "<w:rPr/>";
|
|
181
|
-
return `<w:rPrChange ${
|
|
173
|
+
return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}>${previousRPrXml}</w:rPrChange>`;
|
|
182
174
|
}
|
|
183
175
|
function serializeRunProperties(formatting, propertyChanges) {
|
|
184
176
|
const currentRPrXml = serializeTextFormatting(formatting);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getUnserializedSectionPropertyChildNames } from "../sectionParser.js";
|
|
2
2
|
import { serializeBorder } from "./borderSerializer.js";
|
|
3
|
+
import { serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
3
4
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
5
|
//#region src/docx/serializer/sectionPropertiesSerializer.ts
|
|
6
6
|
const serializeHeaderReference = (ref) => `<w:headerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
7
7
|
const serializeFooterReference = (ref) => `<w:footerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
@@ -133,16 +133,8 @@ function serializeOnOffElement(value, name) {
|
|
|
133
133
|
return value ? `<w:${name}/>` : `<w:${name} w:val="0"/>`;
|
|
134
134
|
}
|
|
135
135
|
function serializeSectionPropertyChange(change) {
|
|
136
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
137
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
138
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
139
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
140
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
141
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
142
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
143
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
144
136
|
const previousSectPrXml = serializeSectionProperties(change.previousProperties) || "<w:sectPr/>";
|
|
145
|
-
return `<w:sectPrChange ${
|
|
137
|
+
return `<w:sectPrChange ${serializeTrackedChangeAttributes(change.info)}>${previousSectPrXml}</w:sectPrChange>`;
|
|
146
138
|
}
|
|
147
139
|
function serializeSectionProperties(props) {
|
|
148
140
|
if (!props) return "";
|
|
@@ -3,8 +3,8 @@ import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
|
3
3
|
import { parseTableCellProperties, parseTableGrid, parseTableProperties, parseTableRowProperties } from "../tableParser.js";
|
|
4
4
|
import { OOXML_NAMESPACE_SCOPE, parseXml } from "../xmlParser.js";
|
|
5
5
|
import { serializeBorder } from "./borderSerializer.js";
|
|
6
|
+
import { serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
6
7
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
7
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
8
8
|
//#region src/docx/serializer/tableSerializer.ts
|
|
9
9
|
/**
|
|
10
10
|
* The captured element with the revision children written back into it.
|
|
@@ -69,25 +69,6 @@ const verifiedSourceXml = (formatting, parse) => {
|
|
|
69
69
|
const reparsed = parse(parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.[0] ?? null);
|
|
70
70
|
return canonicalJson(withoutCaptures(reparsed)) === canonicalJson(withoutCaptures(formatting)) ? sourceXml : null;
|
|
71
71
|
};
|
|
72
|
-
function normalizeTrackedChangeInfo(info) {
|
|
73
|
-
const normalizedId = normalizeRevisionId(info.id);
|
|
74
|
-
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
75
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
76
|
-
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
77
|
-
return {
|
|
78
|
-
id: normalizedId,
|
|
79
|
-
author: normalizedAuthor,
|
|
80
|
-
...normalizedDate !== void 0 ? { date: normalizedDate } : {}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function serializeTrackedChangeAttributes(info, rsid) {
|
|
84
|
-
const normalized = normalizeTrackedChangeInfo(info);
|
|
85
|
-
const attrs = [`w:id="${normalized.id}"`, `w:author="${escapeXml(normalized.author)}"`];
|
|
86
|
-
if (normalized.date) attrs.push(`w:date="${escapeXml(normalized.date)}"`);
|
|
87
|
-
if (info.utcDate) attrs.push(`${info.utcDate.attribute}="${escapeXml(info.utcDate.value)}"`);
|
|
88
|
-
if (rsid && rsid.trim().length > 0) attrs.push(`w:rsid="${escapeXml(rsid.trim())}"`);
|
|
89
|
-
return attrs.join(" ");
|
|
90
|
-
}
|
|
91
72
|
/**
|
|
92
73
|
* Serialize a table measurement (width, height)
|
|
93
74
|
*/
|
|
@@ -231,7 +212,7 @@ function extractTblPrInner(tblPrXml) {
|
|
|
231
212
|
return tblPrXml.slice(9, -10);
|
|
232
213
|
}
|
|
233
214
|
function serializeTablePropertyChange(change) {
|
|
234
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
215
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
235
216
|
const previousTblPrInner = extractTblPrInner(serializeTableFormatting(change.previousFormatting) || "<w:tblPr/>");
|
|
236
217
|
return `<w:tblPrChange ${attrs}>${previousTblPrInner.length > 0 ? `<w:tblPr>${previousTblPrInner}</w:tblPr>` : "<w:tblPr/>"}</w:tblPrChange>`;
|
|
237
218
|
}
|
|
@@ -269,7 +250,7 @@ function extractTrPrInner(trPrXml) {
|
|
|
269
250
|
return trPrXml.slice(8, -9);
|
|
270
251
|
}
|
|
271
252
|
function serializeTableRowPropertyChange(change) {
|
|
272
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
253
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
273
254
|
const previousTrPrInner = extractTrPrInner(serializeTableRowFormatting(change.previousFormatting) || "<w:trPr/>");
|
|
274
255
|
return `<w:trPrChange ${attrs}>${previousTrPrInner.length > 0 ? `<w:trPr>${previousTrPrInner}</w:trPr>` : "<w:trPr/>"}</w:trPrChange>`;
|
|
275
256
|
}
|
|
@@ -333,7 +314,7 @@ function extractTcPrInner(tcPrXml) {
|
|
|
333
314
|
return tcPrXml.slice(8, -9);
|
|
334
315
|
}
|
|
335
316
|
function serializeTableCellPropertyChange(change) {
|
|
336
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
317
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
337
318
|
const previousTcPrInner = extractTcPrInner(serializeTableCellFormatting(change.previousFormatting) || "<w:tcPr/>");
|
|
338
319
|
return `<w:tcPrChange ${attrs}>${previousTcPrInner.length > 0 ? `<w:tcPr>${previousTcPrInner}</w:tcPr>` : "<w:tcPr/>"}</w:tcPrChange>`;
|
|
339
320
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
//#region src/docx/serializer/trackedChangeAttributes.d.ts
|
|
3
|
+
type SerializableTrackedChangeInfo = document_d_exports.TrackedChangeInfo | document_d_exports.PropertyChangeInfo;
|
|
4
|
+
/** Normalized, unescaped attributes in schema order for an XML element or string serializer. */
|
|
5
|
+
declare const trackedChangeAttributeEntries: (info: SerializableTrackedChangeInfo) => readonly (readonly [string, string])[];
|
|
6
|
+
declare const trackedChangeAttributeRecord: (info: SerializableTrackedChangeInfo) => Record<string, string>;
|
|
7
|
+
declare const serializeTrackedChangeAttributes: (info: SerializableTrackedChangeInfo) => string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { serializeTrackedChangeAttributes, trackedChangeAttributeEntries, trackedChangeAttributeRecord };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
2
|
+
import { escapeXml } from "./xmlUtils.js";
|
|
3
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
4
|
+
//#region src/docx/serializer/trackedChangeAttributes.ts
|
|
5
|
+
/** Normalized, unescaped attributes in schema order for an XML element or string serializer. */
|
|
6
|
+
const trackedChangeAttributeEntries = (info) => {
|
|
7
|
+
const author = typeof info.author === "string" ? info.author.trim() : "";
|
|
8
|
+
const date = typeof info.date === "string" ? info.date.trim() : "";
|
|
9
|
+
const rawUtcDate = info.utcDate;
|
|
10
|
+
const utcDate = typeof rawUtcDate === "object" && rawUtcDate !== null && "value" in rawUtcDate && typeof rawUtcDate.value === "string" ? rawUtcDate.value.trim() : "";
|
|
11
|
+
const rsid = "rsid" in info && typeof info.rsid === "string" ? info.rsid.trim() : "";
|
|
12
|
+
const entries = [["w:id", String(normalizeRevisionId(info.id))], ["w:author", author.length > 0 ? author : "Unknown"]];
|
|
13
|
+
if (date.length > 0) entries.push(["w:date", date]);
|
|
14
|
+
if (utcDate.length > 0) entries.push([DATE_UTC_ATTRIBUTE, utcDate]);
|
|
15
|
+
if (rsid.length > 0) entries.push(["w:rsid", rsid]);
|
|
16
|
+
return entries;
|
|
17
|
+
};
|
|
18
|
+
const trackedChangeAttributeRecord = (info) => Object.fromEntries(trackedChangeAttributeEntries(info));
|
|
19
|
+
const serializeTrackedChangeAttributes = (info) => trackedChangeAttributeEntries(info).map(([name, value]) => `${name}="${escapeXml(value)}"`).join(" ");
|
|
20
|
+
//#endregion
|
|
21
|
+
export { serializeTrackedChangeAttributes, trackedChangeAttributeEntries, trackedChangeAttributeRecord };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
2
|
import { getParagraphText } from "../paragraphParser.js";
|
|
3
|
+
import { cloneParagraphWithoutPropertySource } from "../paragraphPropertySource.js";
|
|
3
4
|
import { TaggedError } from "better-result";
|
|
4
5
|
//#region src/docx/server/createBilingualDocument.ts
|
|
5
6
|
/**
|
|
@@ -365,7 +366,6 @@ const createStyleCloner = ({ styleById, suffix, cloner }) => {
|
|
|
365
366
|
};
|
|
366
367
|
};
|
|
367
368
|
const cloneParagraphForTarget = (paragraph, targetParaId, styleCloner, cloner, bookmarkIds) => {
|
|
368
|
-
const { textId: _textId, sectionProperties: _sectionProperties, ...rest } = paragraph;
|
|
369
369
|
const formatting = paragraph.formatting;
|
|
370
370
|
const nextFormatting = formatting && {
|
|
371
371
|
...formatting,
|
|
@@ -379,13 +379,15 @@ const cloneParagraphForTarget = (paragraph, targetParaId, styleCloner, cloner, b
|
|
|
379
379
|
numId: cloner.cloneNumId(formatting.numPrFromStyle.numId)
|
|
380
380
|
} }
|
|
381
381
|
};
|
|
382
|
-
|
|
383
|
-
...rest,
|
|
382
|
+
const cloned = cloneParagraphWithoutPropertySource(paragraph, {
|
|
384
383
|
content: remapClonedBookmarkIds(structuredClone(paragraph.content), bookmarkIds),
|
|
385
384
|
paraId: targetParaId,
|
|
386
385
|
...nextFormatting && { formatting: nextFormatting },
|
|
387
386
|
...paragraph.listRendering && { listRendering: remapListRendering(paragraph.listRendering, cloner) }
|
|
388
|
-
};
|
|
387
|
+
});
|
|
388
|
+
Reflect.deleteProperty(cloned, "textId");
|
|
389
|
+
Reflect.deleteProperty(cloned, "sectionProperties");
|
|
390
|
+
return cloned;
|
|
389
391
|
};
|
|
390
392
|
const createBookmarkIdMinter = (source) => {
|
|
391
393
|
let nextId = 0;
|
|
@@ -526,7 +528,7 @@ const projectParagraphIntoColumn = (paragraph, geometry, sourceWidth, columnWidt
|
|
|
526
528
|
indentLeft = minimumLeftIndent + Math.round(flexibleLeft / flexibleTotal * flexibleMaximum);
|
|
527
529
|
indentRight = maxSideIndent - indentLeft;
|
|
528
530
|
}
|
|
529
|
-
|
|
531
|
+
return cloneParagraphWithoutPropertySource(paragraph, { formatting: {
|
|
530
532
|
...paragraph.formatting,
|
|
531
533
|
...(geometry.indentLeft !== void 0 || minimumLeftIndent > 0) && { indentLeft },
|
|
532
534
|
...geometry.indentRight !== void 0 && { indentRight },
|
|
@@ -536,11 +538,7 @@ const projectParagraphIntoColumn = (paragraph, geometry, sourceWidth, columnWidt
|
|
|
536
538
|
...tab,
|
|
537
539
|
position: Math.min(Math.max(0, Math.round(tab.position * scale)), Math.max(0, columnWidth - MIN_TAB_TRAILING_WIDTH_TWIPS))
|
|
538
540
|
})) }
|
|
539
|
-
};
|
|
540
|
-
return {
|
|
541
|
-
...paragraph,
|
|
542
|
-
formatting
|
|
543
|
-
};
|
|
541
|
+
} });
|
|
544
542
|
};
|
|
545
543
|
const projectSideIndent = (value, scale, maximum) => Math.min(Math.max(0, Math.round((value ?? 0) * scale)), maximum);
|
|
546
544
|
const buildCell = (paragraph) => ({
|
|
@@ -29,6 +29,20 @@ const FOLIO_DOCX_XML_PATCH_PROPOSAL_ISSUE_CODES = Object.freeze([
|
|
|
29
29
|
"base-hash-mismatch",
|
|
30
30
|
"package-inspection-failed"
|
|
31
31
|
]);
|
|
32
|
+
const XML_SAFETY_ISSUE = {
|
|
33
|
+
"doctype-forbidden": {
|
|
34
|
+
code: "xml-doctype-forbidden",
|
|
35
|
+
message: "Replacement XML must not declare a document type."
|
|
36
|
+
},
|
|
37
|
+
"entity-forbidden": {
|
|
38
|
+
code: "xml-not-well-formed",
|
|
39
|
+
message: "Replacement XML contains an invalid entity reference."
|
|
40
|
+
},
|
|
41
|
+
"not-well-formed": {
|
|
42
|
+
code: "xml-not-well-formed",
|
|
43
|
+
message: "Replacement XML must be well formed."
|
|
44
|
+
}
|
|
45
|
+
};
|
|
32
46
|
var InvalidFolioDocxXmlPatchProposalError = class extends TaggedError("InvalidFolioDocxXmlPatchProposalError") {};
|
|
33
47
|
var InvalidFolioDocxXmlPatchProposalOptionsError = class extends TaggedError("InvalidFolioDocxXmlPatchProposalOptionsError") {};
|
|
34
48
|
const SHA256_PATTERN = /^[\da-f]{64}$/u;
|
|
@@ -271,19 +285,14 @@ const evaluateDocxXmlPatchProposal = async ({ bytes, proposal: rawProposal, allo
|
|
|
271
285
|
if (exceedsEncodedPart || totalLimitReported) continue;
|
|
272
286
|
encodedByPath.set(replacement.path, replacementBytes);
|
|
273
287
|
const safetyIssue = getDocxXmlSafetyIssue(replacement.replacementXml);
|
|
274
|
-
if (safetyIssue
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
message: "Replacement XML must be well formed.",
|
|
283
|
-
proposalPath: `${proposalPath}.replacementXml`,
|
|
284
|
-
part: replacement.path
|
|
285
|
-
});
|
|
286
|
-
else {
|
|
288
|
+
if (safetyIssue !== null) {
|
|
289
|
+
const issue = XML_SAFETY_ISSUE[safetyIssue];
|
|
290
|
+
issues.push({
|
|
291
|
+
...issue,
|
|
292
|
+
proposalPath: `${proposalPath}.replacementXml`,
|
|
293
|
+
part: replacement.path
|
|
294
|
+
});
|
|
295
|
+
} else {
|
|
287
296
|
const declaredEncoding = replacement.replacementXml.match(XML_DECLARED_ENCODING_PATTERN)?.at(1);
|
|
288
297
|
if (declaredEncoding !== void 0 && declaredEncoding.toLowerCase() !== "utf-8" && declaredEncoding.toLowerCase() !== "utf8") issues.push({
|
|
289
298
|
code: "xml-encoding-mismatch",
|