@stll/folio-core 0.37.4 → 0.37.5
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/index.d.ts +2 -1
- package/dist/ai-edits/types.d.ts +2 -2
- package/dist/compare/content-alignment.js +213 -135
- package/dist/compare/content-types.d.ts +3 -1
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/docx/numberingParser.d.ts +1 -13
- package/dist/docx/numberingParser.js +1 -10
- package/dist/docx/paragraphParser.js +1 -5
- package/dist/docx/paragraphPropertySource.d.ts +8 -5
- package/dist/docx/paragraphPropertySource.js +16 -4
- package/dist/docx/serializer/borderSerializer.d.ts +4 -1
- package/dist/docx/serializer/borderSerializer.js +20 -18
- package/dist/docx/serializer/commentSerializer.js +1 -1
- package/dist/docx/serializer/numberingSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +11 -177
- package/dist/docx/serializer/runSerializer.d.ts +1 -5
- package/dist/docx/serializer/runSerializer.js +2 -129
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/textFormattingSerializer.d.ts +17 -0
- package/dist/docx/serializer/textFormattingSerializer.js +142 -0
- package/dist/index.d.ts +2 -2
- package/dist/internal/paragraphFormattingSerialization.d.ts +23 -0
- package/dist/internal/paragraphFormattingSerialization.js +157 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +8 -16
- package/dist/server.d.ts +2 -1
- package/dist/version-comparison.js +23 -27
- package/package.json +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { ModeledParagraphFormattingEmission } from "../internal/paragraphFormattingSerialization.js";
|
|
2
3
|
import { Transaction } from "prosemirror-state";
|
|
3
4
|
import { Fragment, Mark, Node, NodeType } from "prosemirror-model";
|
|
4
5
|
//#region src/docx/paragraphPropertySource.d.ts
|
|
5
|
-
|
|
6
|
+
declare const paragraphPropertySourceEmissionFingerprint: unique symbol;
|
|
7
|
+
type ParagraphPropertySource = Readonly<{
|
|
6
8
|
xml: string;
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
+
[paragraphPropertySourceEmissionFingerprint]: string;
|
|
10
|
+
}>;
|
|
9
11
|
declare const PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR = "_docxParagraphSourceToken";
|
|
10
12
|
declare const PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR = "_docxParagraphSourceContract";
|
|
11
13
|
/** Durable identity nested inside opaque collapsed-cell ProseMirror attrs; stripped on restore. */
|
|
@@ -26,8 +28,9 @@ declare const isParagraphPropertySourceToken: (token: unknown) => token is strin
|
|
|
26
28
|
declare const paragraphPropertySourceTokenMatchesContract: (token: unknown, contract: string) => token is string;
|
|
27
29
|
/** Visit the v1 provenance scope in canonical OOXML body-story order. */
|
|
28
30
|
declare const visitDocumentStoryParagraphs: (content: document_d_exports.Document["package"]["document"]["content"], visit: (paragraph: document_d_exports.Paragraph) => void) => void;
|
|
29
|
-
declare const assignParagraphPropertySource: (paragraph: document_d_exports.Paragraph,
|
|
31
|
+
declare const assignParagraphPropertySource: (paragraph: document_d_exports.Paragraph, xml: string) => void;
|
|
30
32
|
declare const getParagraphPropertySource: (paragraph: document_d_exports.Paragraph) => ParagraphPropertySource | undefined;
|
|
33
|
+
declare const paragraphPropertySourceMatchesEmission: (source: ParagraphPropertySource, emission: ModeledParagraphFormattingEmission) => boolean;
|
|
31
34
|
/** Copy the captured `w:pPr` without claiming the source paragraph's durable identity. */
|
|
32
35
|
declare const copyParagraphPropertyCapture: (target: document_d_exports.Paragraph, source: document_d_exports.Paragraph) => void;
|
|
33
36
|
declare const copyParagraphPropertySource: (target: document_d_exports.Paragraph, source: document_d_exports.Paragraph) => void;
|
|
@@ -126,4 +129,4 @@ declare const linkParagraphPropertySourceCandidate: (target: document_d_exports.
|
|
|
126
129
|
declare const getParagraphPropertySourceCandidate: (paragraph: document_d_exports.Paragraph) => document_d_exports.Paragraph | undefined;
|
|
127
130
|
declare const getParagraphPropertySourceTransferId: (paragraph: document_d_exports.Paragraph) => string | undefined;
|
|
128
131
|
//#endregion
|
|
129
|
-
export { DecodedTableCellParagraphSourcePayload, PARAGRAPH_PROPERTY_SOURCE_VALIDATION_CODES, PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, ParagraphPropertySourceValidationCode, ParagraphPropertySourceValidationError, TABLE_CELL_PARAGRAPH_SOURCE_BINDING_ATTR, TABLE_CELL_PARAGRAPH_SOURCE_PAYLOAD_ERROR_CLASSIFICATIONS, TableCellParagraphPropertySourceBinding, TableCellParagraphSourcePayloadErrorClassification, assignDocumentParagraphPropertySourceContract, assignParagraphPropertySource, cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, cloneParagraphWithoutPropertySource, cloneTableCellsWithParagraphPropertyCaptures, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, createProseParagraphWithPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getExplicitParagraphPropertySourceTransfers, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, joinProseParagraphsWithRightPropertySource, linkParagraphPropertySourceCandidate, linkProseParagraphPropertySource, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithDetachedParagraphPropertySource, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource, transportTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings };
|
|
132
|
+
export { DecodedTableCellParagraphSourcePayload, PARAGRAPH_PROPERTY_SOURCE_VALIDATION_CODES, PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, ParagraphPropertySourceValidationCode, ParagraphPropertySourceValidationError, TABLE_CELL_PARAGRAPH_SOURCE_BINDING_ATTR, TABLE_CELL_PARAGRAPH_SOURCE_PAYLOAD_ERROR_CLASSIFICATIONS, TableCellParagraphPropertySourceBinding, TableCellParagraphSourcePayloadErrorClassification, assignDocumentParagraphPropertySourceContract, assignParagraphPropertySource, cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, cloneParagraphWithoutPropertySource, cloneTableCellsWithParagraphPropertyCaptures, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, createProseParagraphWithPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getExplicitParagraphPropertySourceTransfers, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, joinProseParagraphsWithRightPropertySource, linkParagraphPropertySourceCandidate, linkProseParagraphPropertySource, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceMatchesEmission, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithDetachedParagraphPropertySource, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource, transportTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings };
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
import { modelParagraphFormattingEmission } from "../internal/paragraphFormattingSerialization.js";
|
|
2
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
1
3
|
import { visitDocxParagraphs } from "./paragraphTraversal.js";
|
|
2
4
|
import { TaggedError, panic } from "better-result";
|
|
3
5
|
import { PluginKey } from "prosemirror-state";
|
|
4
6
|
//#region src/docx/paragraphPropertySource.ts
|
|
7
|
+
const paragraphPropertySourceEmissionFingerprint = Symbol("paragraphPropertySourceEmissionFingerprint");
|
|
5
8
|
const paragraphPropertySources = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
const paragraphFormattingEmissionFingerprint = (emission) => canonicalJson(emission);
|
|
10
|
+
const ownedParagraphPropertySource = (paragraph, xml) => {
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
xml,
|
|
13
|
+
[paragraphPropertySourceEmissionFingerprint]: paragraphFormattingEmissionFingerprint(modelParagraphFormattingEmission(paragraph.formatting))
|
|
14
|
+
});
|
|
15
|
+
};
|
|
6
16
|
const paragraphPropertySourceOwners = /* @__PURE__ */ new WeakMap();
|
|
7
17
|
const proseParagraphSourceOwners = /* @__PURE__ */ new WeakMap();
|
|
8
18
|
const paragraphPropertySourceCandidates = /* @__PURE__ */ new WeakMap();
|
|
@@ -80,16 +90,18 @@ const paragraphPropertySourceTokenMatchesContract = (token, contract) => {
|
|
|
80
90
|
const visitDocumentStoryParagraphs = (content, visit) => {
|
|
81
91
|
visitDocxParagraphs({ documentBody: { content } }, visit);
|
|
82
92
|
};
|
|
83
|
-
const assignParagraphPropertySource = (paragraph,
|
|
84
|
-
paragraphPropertySources.set(paragraph,
|
|
93
|
+
const assignParagraphPropertySource = (paragraph, xml) => {
|
|
94
|
+
paragraphPropertySources.set(paragraph, ownedParagraphPropertySource(paragraph, xml));
|
|
85
95
|
paragraphPropertySourceOwners.set(paragraph, paragraph);
|
|
86
96
|
};
|
|
87
97
|
const getParagraphPropertySource = (paragraph) => paragraphPropertySources.get(paragraph);
|
|
98
|
+
const paragraphPropertySourceMatchesEmission = (source, emission) => source[paragraphPropertySourceEmissionFingerprint] === paragraphFormattingEmissionFingerprint(emission);
|
|
88
99
|
/** Copy the captured `w:pPr` without claiming the source paragraph's durable identity. */
|
|
89
100
|
const copyParagraphPropertyCapture = (target, source) => {
|
|
90
101
|
const propertySource = paragraphPropertySources.get(source);
|
|
91
102
|
if (propertySource) {
|
|
92
|
-
|
|
103
|
+
const copiedSource = Object.freeze({ ...propertySource });
|
|
104
|
+
paragraphPropertySources.set(target, copiedSource);
|
|
93
105
|
paragraphPropertySourceOwners.set(target, paragraphPropertySourceOwners.get(source) ?? source);
|
|
94
106
|
}
|
|
95
107
|
};
|
|
@@ -676,4 +688,4 @@ const linkParagraphPropertySourceCandidate = (target, source) => {
|
|
|
676
688
|
const getParagraphPropertySourceCandidate = (paragraph) => paragraphPropertySourceCandidates.get(paragraph);
|
|
677
689
|
const getParagraphPropertySourceTransferId = (paragraph) => paragraphPropertySourceTransferIds.get(paragraph);
|
|
678
690
|
//#endregion
|
|
679
|
-
export { PARAGRAPH_PROPERTY_SOURCE_VALIDATION_CODES, PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, ParagraphPropertySourceValidationError, TABLE_CELL_PARAGRAPH_SOURCE_BINDING_ATTR, TABLE_CELL_PARAGRAPH_SOURCE_PAYLOAD_ERROR_CLASSIFICATIONS, assignDocumentParagraphPropertySourceContract, assignParagraphPropertySource, cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, cloneParagraphWithoutPropertySource, cloneTableCellsWithParagraphPropertyCaptures, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, createProseParagraphWithPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getExplicitParagraphPropertySourceTransfers, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, joinProseParagraphsWithRightPropertySource, linkParagraphPropertySourceCandidate, linkProseParagraphPropertySource, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithDetachedParagraphPropertySource, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource, transportTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings };
|
|
691
|
+
export { PARAGRAPH_PROPERTY_SOURCE_VALIDATION_CODES, PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, ParagraphPropertySourceValidationError, TABLE_CELL_PARAGRAPH_SOURCE_BINDING_ATTR, TABLE_CELL_PARAGRAPH_SOURCE_PAYLOAD_ERROR_CLASSIFICATIONS, assignDocumentParagraphPropertySourceContract, assignParagraphPropertySource, cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, cloneParagraphWithoutPropertySource, cloneTableCellsWithParagraphPropertyCaptures, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, createProseParagraphWithPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getExplicitParagraphPropertySourceTransfers, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, joinProseParagraphsWithRightPropertySource, linkParagraphPropertySourceCandidate, linkProseParagraphPropertySource, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceMatchesEmission, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithDetachedParagraphPropertySource, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource, transportTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
2
|
//#region src/docx/serializer/borderSerializer.d.ts
|
|
3
|
+
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
|
+
type ClassifiedBorderField = "style" | "color" | "size" | "space" | "shadow" | "frame" | "artRelationshipId" | "topLeftArtRelationshipId" | "topRightArtRelationshipId" | "bottomLeftArtRelationshipId" | "bottomRightArtRelationshipId";
|
|
5
|
+
type ExhaustiveBorder = ExhaustiveFields<document_d_exports.BorderSpec, ClassifiedBorderField>;
|
|
3
6
|
/**
|
|
4
7
|
* Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
|
|
5
8
|
*
|
|
@@ -19,6 +22,6 @@ import { document_d_exports } from "../../types/document.js";
|
|
|
19
22
|
* untrusted and are `escapeXml`'d before re-entering XML attributes; for valid
|
|
20
23
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
21
24
|
*/
|
|
22
|
-
declare function serializeBorder(
|
|
25
|
+
declare function serializeBorder(input: ExhaustiveBorder | undefined, elementName: string): string;
|
|
23
26
|
//#endregion
|
|
24
27
|
export { serializeBorder };
|
|
@@ -19,25 +19,27 @@ import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
|
19
19
|
* untrusted and are `escapeXml`'d before re-entering XML attributes; for valid
|
|
20
20
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
21
21
|
*/
|
|
22
|
-
function serializeBorder(
|
|
23
|
-
if (!
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
if (
|
|
32
|
-
if (
|
|
22
|
+
function serializeBorder(input, elementName) {
|
|
23
|
+
if (!input) return "";
|
|
24
|
+
const { style, color, size, space, shadow, frame, artRelationshipId, topLeftArtRelationshipId, topRightArtRelationshipId, bottomLeftArtRelationshipId, bottomRightArtRelationshipId } = input;
|
|
25
|
+
const attrs = [`w:val="${escapeXml(style)}"`];
|
|
26
|
+
if (size !== void 0) attrs.push(`w:sz="${intAttr(size)}"`);
|
|
27
|
+
if (space !== void 0) attrs.push(`w:space="${intAttr(space)}"`);
|
|
28
|
+
if (color) {
|
|
29
|
+
const { auto, rgb, themeColor, themeTint, themeShade } = color;
|
|
30
|
+
if (auto) attrs.push("w:color=\"auto\"");
|
|
31
|
+
else if (rgb) attrs.push(`w:color="${escapeXml(rgb)}"`);
|
|
32
|
+
if (themeColor) attrs.push(`w:themeColor="${escapeXml(themeColor)}"`);
|
|
33
|
+
if (themeTint) attrs.push(`w:themeTint="${escapeXml(themeTint)}"`);
|
|
34
|
+
if (themeShade) attrs.push(`w:themeShade="${escapeXml(themeShade)}"`);
|
|
33
35
|
}
|
|
34
|
-
if (
|
|
35
|
-
if (
|
|
36
|
-
if (
|
|
37
|
-
if (
|
|
38
|
-
if (
|
|
39
|
-
if (
|
|
40
|
-
if (
|
|
36
|
+
if (shadow) attrs.push("w:shadow=\"true\"");
|
|
37
|
+
if (frame) attrs.push("w:frame=\"true\"");
|
|
38
|
+
if (artRelationshipId) attrs.push(`w:id="${escapeXml(artRelationshipId)}"`);
|
|
39
|
+
if (topLeftArtRelationshipId) attrs.push(`w:topLeft="${escapeXml(topLeftArtRelationshipId)}"`);
|
|
40
|
+
if (topRightArtRelationshipId) attrs.push(`w:topRight="${escapeXml(topRightArtRelationshipId)}"`);
|
|
41
|
+
if (bottomLeftArtRelationshipId) attrs.push(`w:bottomLeft="${escapeXml(bottomLeftArtRelationshipId)}"`);
|
|
42
|
+
if (bottomRightArtRelationshipId) attrs.push(`w:bottomRight="${escapeXml(bottomRightArtRelationshipId)}"`);
|
|
41
43
|
return `<w:${elementName} ${attrs.join(" ")}/>`;
|
|
42
44
|
}
|
|
43
45
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
3
|
import { serializePartElement } from "./partNamespaces.js";
|
|
4
|
-
import { serializeTextFormatting } from "./
|
|
4
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
5
5
|
import { escapeXml } from "./xmlUtils.js";
|
|
6
6
|
//#region src/docx/serializer/commentSerializer.ts
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { serializePartElement } from "./partNamespaces.js";
|
|
2
|
-
import { serializeTextFormatting } from "./
|
|
2
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
3
3
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
4
|
//#region src/docx/serializer/numberingSerializer.ts
|
|
5
5
|
/**
|
|
@@ -1,142 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { numPrEqual } from "../numberingParser.js";
|
|
4
|
-
import { getParagraphPropertySource } from "../paragraphPropertySource.js";
|
|
1
|
+
import { modelParagraphFormattingEmission } from "../../internal/paragraphFormattingSerialization.js";
|
|
2
|
+
import { getParagraphPropertySource, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
|
|
5
3
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
6
4
|
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
7
5
|
import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
|
|
8
6
|
import { captureVerbatimXml, sanitizeCapturedXmlElement } from "../verbatimCapture.js";
|
|
9
7
|
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
10
|
-
import {
|
|
11
|
-
import { serializeRun, serializeTextFormatting } from "./runSerializer.js";
|
|
8
|
+
import { serializeRun } from "./runSerializer.js";
|
|
12
9
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
10
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
13
11
|
import { serializeTrackedChangeAttributes, trackedChangeAttributeRecord } from "./trackedChangeAttributes.js";
|
|
14
|
-
import { escapeXml,
|
|
12
|
+
import { escapeXml, isSingleWellFormedElement } from "./xmlUtils.js";
|
|
15
13
|
import { panic } from "better-result";
|
|
16
14
|
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
17
15
|
//#region src/docx/serializer/paragraphSerializer.ts
|
|
18
16
|
/**
|
|
19
|
-
* Serialize paragraph borders (w:pBdr)
|
|
20
|
-
*/
|
|
21
|
-
function serializeParagraphBorders(borders) {
|
|
22
|
-
if (!borders) return "";
|
|
23
|
-
const parts = [];
|
|
24
|
-
if (borders.top) {
|
|
25
|
-
const topXml = serializeBorder(borders.top, "top");
|
|
26
|
-
if (topXml) parts.push(topXml);
|
|
27
|
-
}
|
|
28
|
-
if (borders.left) {
|
|
29
|
-
const leftXml = serializeBorder(borders.left, "left");
|
|
30
|
-
if (leftXml) parts.push(leftXml);
|
|
31
|
-
}
|
|
32
|
-
if (borders.bottom) {
|
|
33
|
-
const bottomXml = serializeBorder(borders.bottom, "bottom");
|
|
34
|
-
if (bottomXml) parts.push(bottomXml);
|
|
35
|
-
}
|
|
36
|
-
if (borders.right) {
|
|
37
|
-
const rightXml = serializeBorder(borders.right, "right");
|
|
38
|
-
if (rightXml) parts.push(rightXml);
|
|
39
|
-
}
|
|
40
|
-
if (borders.between) {
|
|
41
|
-
const betweenXml = serializeBorder(borders.between, "between");
|
|
42
|
-
if (betweenXml) parts.push(betweenXml);
|
|
43
|
-
}
|
|
44
|
-
if (borders.bar) {
|
|
45
|
-
const barXml = serializeBorder(borders.bar, "bar");
|
|
46
|
-
if (barXml) parts.push(barXml);
|
|
47
|
-
}
|
|
48
|
-
if (parts.length === 0) return "";
|
|
49
|
-
return `<w:pBdr>${parts.join("")}</w:pBdr>`;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Serialize shading properties (w:shd)
|
|
53
|
-
*/
|
|
54
|
-
function serializeShading(shading) {
|
|
55
|
-
if (!shading) return "";
|
|
56
|
-
const attrs = [];
|
|
57
|
-
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
58
|
-
else attrs.push("w:val=\"clear\"");
|
|
59
|
-
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
60
|
-
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
61
|
-
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
62
|
-
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
63
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
64
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
65
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
66
|
-
if (attrs.length === 0) return "";
|
|
67
|
-
return `<w:shd ${attrs.join(" ")}/>`;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Serialize tab stops (w:tabs)
|
|
71
|
-
*/
|
|
72
|
-
function serializeTabStops(tabs) {
|
|
73
|
-
if (!tabs || tabs.length === 0) return "";
|
|
74
|
-
return `<w:tabs>${tabs.map((tab) => {
|
|
75
|
-
const attrs = [`w:val="${tab.alignment}"`, `w:pos="${intAttr(tab.position)}"`];
|
|
76
|
-
if (tab.leader && tab.leader !== "none") attrs.push(`w:leader="${tab.leader}"`);
|
|
77
|
-
return `<w:tab ${attrs.join(" ")}/>`;
|
|
78
|
-
}).join("")}</w:tabs>`;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Serialize spacing properties (w:spacing)
|
|
82
|
-
*/
|
|
83
|
-
function serializeSpacing(formatting) {
|
|
84
|
-
const attrs = [];
|
|
85
|
-
if (formatting.spaceBefore !== void 0) attrs.push(`w:before="${intAttr(formatting.spaceBefore)}"`);
|
|
86
|
-
if (formatting.spaceAfter !== void 0) attrs.push(`w:after="${intAttr(formatting.spaceAfter)}"`);
|
|
87
|
-
if (formatting.lineSpacing !== void 0) attrs.push(`w:line="${intAttr(formatting.lineSpacing)}"`);
|
|
88
|
-
if (formatting.lineSpacingRule) attrs.push(`w:lineRule="${formatting.lineSpacingRule}"`);
|
|
89
|
-
if (formatting.beforeAutospacing !== void 0) attrs.push(`w:beforeAutospacing="${formatting.beforeAutospacing ? "1" : "0"}"`);
|
|
90
|
-
if (formatting.afterAutospacing !== void 0) attrs.push(`w:afterAutospacing="${formatting.afterAutospacing ? "1" : "0"}"`);
|
|
91
|
-
if (attrs.length === 0) return "";
|
|
92
|
-
return `<w:spacing ${attrs.join(" ")}/>`;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Serialize indentation properties (w:ind)
|
|
96
|
-
*/
|
|
97
|
-
function serializeIndentation(formatting) {
|
|
98
|
-
const attrs = [];
|
|
99
|
-
if (formatting.indentLeft !== void 0) attrs.push(`w:left="${intAttr(formatting.indentLeft)}"`);
|
|
100
|
-
if (formatting.indentRight !== void 0) attrs.push(`w:right="${intAttr(formatting.indentRight)}"`);
|
|
101
|
-
if (formatting.indentFirstLine !== void 0) if (formatting.hangingIndent) attrs.push(`w:hanging="${intAttr(Math.abs(formatting.indentFirstLine))}"`);
|
|
102
|
-
else attrs.push(`w:firstLine="${intAttr(formatting.indentFirstLine)}"`);
|
|
103
|
-
if (attrs.length === 0) return "";
|
|
104
|
-
return `<w:ind ${attrs.join(" ")}/>`;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Serialize numbering properties (w:numPr)
|
|
108
|
-
*/
|
|
109
|
-
function serializeNumbering(numPr) {
|
|
110
|
-
if (!numPr) return "";
|
|
111
|
-
const parts = [];
|
|
112
|
-
if (numPr.ilvl !== void 0) parts.push(`<w:ilvl w:val="${intAttr(numPr.ilvl)}"/>`);
|
|
113
|
-
if (numPr.numId !== void 0) parts.push(`<w:numId w:val="${intAttr(numPr.numId)}"/>`);
|
|
114
|
-
if (parts.length === 0) return "";
|
|
115
|
-
return `<w:numPr>${parts.join("")}</w:numPr>`;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Serialize frame properties (w:framePr)
|
|
119
|
-
*/
|
|
120
|
-
function serializeFrameProperties(frame) {
|
|
121
|
-
if (!frame) return "";
|
|
122
|
-
const attrs = [];
|
|
123
|
-
if (frame.dropCap) attrs.push(`w:dropCap="${frame.dropCap}"`);
|
|
124
|
-
if (frame.lines !== void 0) attrs.push(`w:lines="${intAttr(frame.lines)}"`);
|
|
125
|
-
if (frame.width !== void 0) attrs.push(`w:w="${intAttr(frame.width)}"`);
|
|
126
|
-
if (frame.height !== void 0) attrs.push(`w:h="${intAttr(frame.height)}"`);
|
|
127
|
-
if (frame.hSpace !== void 0) attrs.push(`w:hSpace="${intAttr(frame.hSpace)}"`);
|
|
128
|
-
if (frame.vSpace !== void 0) attrs.push(`w:vSpace="${intAttr(frame.vSpace)}"`);
|
|
129
|
-
if (frame.hAnchor) attrs.push(`w:hAnchor="${frame.hAnchor}"`);
|
|
130
|
-
if (frame.vAnchor) attrs.push(`w:vAnchor="${frame.vAnchor}"`);
|
|
131
|
-
if (frame.x !== void 0) attrs.push(`w:x="${frame.x}"`);
|
|
132
|
-
if (frame.y !== void 0) attrs.push(`w:y="${frame.y}"`);
|
|
133
|
-
if (frame.xAlign) attrs.push(`w:xAlign="${frame.xAlign}"`);
|
|
134
|
-
if (frame.yAlign) attrs.push(`w:yAlign="${frame.yAlign}"`);
|
|
135
|
-
if (frame.wrap) attrs.push(`w:wrap="${frame.wrap}"`);
|
|
136
|
-
if (attrs.length === 0) return "";
|
|
137
|
-
return `<w:framePr ${attrs.join(" ")}/>`;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
17
|
* Serialize paragraph formatting properties to w:pPr XML
|
|
141
18
|
*/
|
|
142
19
|
function serializeParagraphMarkChange(mark) {
|
|
@@ -361,7 +238,7 @@ const verifiedParagraphPropertySource = (formatting, source) => {
|
|
|
361
238
|
if (!source) return null;
|
|
362
239
|
const replayableSource = replayableParagraphPropertySourceXml(source.xml);
|
|
363
240
|
if (replayableSource === null) return null;
|
|
364
|
-
return
|
|
241
|
+
return paragraphPropertySourceMatchesEmission(source, formatting) ? replayableSource : null;
|
|
365
242
|
};
|
|
366
243
|
const withTrailingParagraphPropertyChildren = (sourceXml, children) => {
|
|
367
244
|
const written = children.join("");
|
|
@@ -398,6 +275,7 @@ const withParagraphMarkChange = (sourceXml, mark) => {
|
|
|
398
275
|
return captureVerbatimXml(cloneElement(root, { elements }));
|
|
399
276
|
};
|
|
400
277
|
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sectionProperties } = {}) => {
|
|
278
|
+
const modeledFormatting = modelParagraphFormattingEmission(formatting);
|
|
401
279
|
const serializablePropertyChangeCount = propertyChanges?.length ?? 0;
|
|
402
280
|
if (serializablePropertyChangeCount > 1) panic("A paragraph cannot serialize more than one w:pPrChange", { count: serializablePropertyChangeCount });
|
|
403
281
|
const paragraphMarkXml = paragraphMarkChange ? serializeParagraphMarkChange(paragraphMarkChange) : "";
|
|
@@ -408,50 +286,15 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
408
286
|
sectionPropertiesXml,
|
|
409
287
|
...propertyChangesXml
|
|
410
288
|
].some((xml) => xml.includes(`${DATE_UTC_ATTRIBUTE}=`));
|
|
411
|
-
const verifiedSource = verifiedParagraphPropertySource(
|
|
289
|
+
const verifiedSource = verifiedParagraphPropertySource(modeledFormatting, propertySource);
|
|
412
290
|
if (verifiedSource !== null && (!composedChildrenUseDateUtc || !sourceShadowsDateUtcPrefix(verifiedSource))) {
|
|
413
291
|
const sourceWithMark = paragraphMarkChange ? withParagraphMarkChange(verifiedSource, paragraphMarkChange) : verifiedSource;
|
|
414
292
|
return withTrailingParagraphPropertyChildren(sourceWithMark, [sectionPropertiesXml, ...propertyChangesXml]);
|
|
415
293
|
}
|
|
416
294
|
const parts = [];
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
};
|
|
421
|
-
if (formatting) {
|
|
422
|
-
if (formatting.styleId) parts.push(`<w:pStyle w:val="${escapeXml(formatting.styleId)}"/>`);
|
|
423
|
-
pushToggle("keepNext", formatting.keepNext);
|
|
424
|
-
pushToggle("keepLines", formatting.keepLines);
|
|
425
|
-
pushToggle("pageBreakBefore", formatting.pageBreakBefore);
|
|
426
|
-
const frameXml = serializeFrameProperties(formatting.frame);
|
|
427
|
-
if (frameXml) parts.push(frameXml);
|
|
428
|
-
pushToggle("widowControl", formatting.widowControl);
|
|
429
|
-
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
430
|
-
if (numPrXml) parts.push(numPrXml);
|
|
431
|
-
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
432
|
-
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
433
|
-
if (bordersXml) parts.push(bordersXml);
|
|
434
|
-
const shadingXml = serializeShading(formatting.shading);
|
|
435
|
-
if (shadingXml) parts.push(shadingXml);
|
|
436
|
-
const tabsXml = serializeTabStops(formatting.tabs);
|
|
437
|
-
if (tabsXml) parts.push(tabsXml);
|
|
438
|
-
pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
|
|
439
|
-
pushToggle("kinsoku", formatting.kinsoku);
|
|
440
|
-
pushToggle("overflowPunct", formatting.overflowPunctuation);
|
|
441
|
-
pushToggle("bidi", formatting.bidi);
|
|
442
|
-
pushToggle("snapToGrid", formatting.snapToGrid);
|
|
443
|
-
const spacingXml = serializeSpacing(formatting);
|
|
444
|
-
if (spacingXml) parts.push(spacingXml);
|
|
445
|
-
const indXml = serializeIndentation(formatting);
|
|
446
|
-
if (indXml) parts.push(indXml);
|
|
447
|
-
pushToggle("contextualSpacing", formatting.contextualSpacing);
|
|
448
|
-
if (formatting.alignment) parts.push(`<w:jc w:val="${formatting.alignment}"/>`);
|
|
449
|
-
if (formatting.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${formatting.outlineLevel}"/>`);
|
|
450
|
-
if (paragraphMarkChange || formatting.runProperties || formatting.runInWithNext) {
|
|
451
|
-
const fullInner = `${paragraphMarkChange ? paragraphMarkXml : ""}${formatting.runProperties ? extractRPrInner(serializeTextFormatting(formatting.runProperties)) : ""}${formatting.runInWithNext ? "<w:specVanish/>" : ""}`;
|
|
452
|
-
if (fullInner.length > 0) parts.push(`<w:rPr>${fullInner}</w:rPr>`);
|
|
453
|
-
}
|
|
454
|
-
} else if (paragraphMarkChange) parts.push(`<w:rPr>${paragraphMarkXml}</w:rPr>`);
|
|
295
|
+
if (modeledFormatting.propertiesXml) parts.push(modeledFormatting.propertiesXml);
|
|
296
|
+
const paragraphMarkPropertiesInnerXml = `${paragraphMarkXml}${modeledFormatting.paragraphMarkPropertiesInnerXml ?? ""}`;
|
|
297
|
+
if (paragraphMarkPropertiesInnerXml) parts.push(`<w:rPr>${paragraphMarkPropertiesInnerXml}</w:rPr>`);
|
|
455
298
|
parts.push(sectionPropertiesXml);
|
|
456
299
|
if (propertyChangesXml.length > 0) parts.push(...propertyChangesXml);
|
|
457
300
|
const inner = parts.join("");
|
|
@@ -468,15 +311,6 @@ function extractPPrInner(pPrXml) {
|
|
|
468
311
|
if (!pPrXml.startsWith("<w:pPr>") || !pPrXml.endsWith("</w:pPr>")) return "";
|
|
469
312
|
return pPrXml.slice(7, -8);
|
|
470
313
|
}
|
|
471
|
-
/**
|
|
472
|
-
* Strip the outer `<w:rPr>...</w:rPr>` wrapper so callers can splice
|
|
473
|
-
* additional rPr children (e.g. `<w:specVanish/>`) and re-emit a
|
|
474
|
-
* single rPr element.
|
|
475
|
-
*/
|
|
476
|
-
function extractRPrInner(rPrXml) {
|
|
477
|
-
if (!rPrXml.startsWith("<w:rPr>") || !rPrXml.endsWith("</w:rPr>")) return "";
|
|
478
|
-
return rPrXml.slice(7, -8);
|
|
479
|
-
}
|
|
480
314
|
function serializeParagraphPropertyChange(change) {
|
|
481
315
|
const previousPPrInner = extractPPrInner(serializeParagraphFormatting(change.previousFormatting) || "<w:pPr/>");
|
|
482
316
|
const normalizedPreviousPPr = previousPPrInner.length > 0 ? `<w:pPr>${previousPPrInner}</w:pPr>` : "<w:pPr/>";
|
|
@@ -5,10 +5,6 @@ import { document_d_exports } from "../../types/document.js";
|
|
|
5
5
|
* to keep IDs deterministic across saves.
|
|
6
6
|
*/
|
|
7
7
|
declare function resetAutoIdCounter(): void;
|
|
8
|
-
/**
|
|
9
|
-
* Serialize text formatting properties to w:rPr XML
|
|
10
|
-
*/
|
|
11
|
-
declare function serializeTextFormatting(formatting: document_d_exports.TextFormatting | undefined): string;
|
|
12
8
|
/**
|
|
13
9
|
* Serialize a run to OOXML XML (w:r)
|
|
14
10
|
*
|
|
@@ -52,4 +48,4 @@ declare function createBreakRun(breakType?: "page" | "column" | "textWrapping",
|
|
|
52
48
|
*/
|
|
53
49
|
declare function createTabRun(formatting?: document_d_exports.TextFormatting): document_d_exports.Run;
|
|
54
50
|
//#endregion
|
|
55
|
-
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns
|
|
51
|
+
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns };
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { HIGHLIGHT_COLOR_VALUES } from "../../types/documentEnumValues.js";
|
|
2
1
|
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
3
|
-
import { roundHorizontalScalePercentForSerialization } from "../../utils/horizontalScale.js";
|
|
4
2
|
import { THEME_COLOR_TO_DRAWING_SCHEME } from "../drawingUtils.js";
|
|
5
3
|
import { requiresXmlSpacePreserve } from "../textWhitespace.js";
|
|
6
4
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
7
5
|
import { serializeTable } from "./tableSerializer.js";
|
|
6
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
8
7
|
import { getSingularRunPropertyChange, serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
9
8
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
10
9
|
import { panic } from "better-result";
|
|
@@ -38,132 +37,6 @@ function getUniqueId(id) {
|
|
|
38
37
|
if (id !== void 0 && id !== "" && id !== 0) return String(id);
|
|
39
38
|
return String(nextAutoId++);
|
|
40
39
|
}
|
|
41
|
-
/** Valid OOXML highlight color names (ECMA-376 §17.18.40) */
|
|
42
|
-
const VALID_HIGHLIGHT_COLORS = new Set(HIGHLIGHT_COLOR_VALUES);
|
|
43
|
-
/**
|
|
44
|
-
* Serialize a color element (w:color)
|
|
45
|
-
*/
|
|
46
|
-
function serializeColorElement(color) {
|
|
47
|
-
if (!color) return "";
|
|
48
|
-
const attrs = [];
|
|
49
|
-
if (color.auto) attrs.push("w:val=\"auto\"");
|
|
50
|
-
else if (color.rgb && isValidHexColor(color.rgb)) attrs.push(`w:val="${escapeXml(color.rgb)}"`);
|
|
51
|
-
if (color.themeColor) attrs.push(`w:themeColor="${escapeXml(color.themeColor)}"`);
|
|
52
|
-
if (color.themeTint) attrs.push(`w:themeTint="${escapeXml(color.themeTint)}"`);
|
|
53
|
-
if (color.themeShade) attrs.push(`w:themeShade="${escapeXml(color.themeShade)}"`);
|
|
54
|
-
if (attrs.length === 0) return "";
|
|
55
|
-
return `<w:color ${attrs.join(" ")}/>`;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Serialize shading properties (w:shd)
|
|
59
|
-
*/
|
|
60
|
-
function serializeShading(shading) {
|
|
61
|
-
if (!shading) return "";
|
|
62
|
-
const attrs = [];
|
|
63
|
-
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
64
|
-
else attrs.push("w:val=\"clear\"");
|
|
65
|
-
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
66
|
-
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
67
|
-
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
68
|
-
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
69
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
70
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
71
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
72
|
-
if (attrs.length === 0) return "";
|
|
73
|
-
return `<w:shd ${attrs.join(" ")}/>`;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Serialize text formatting properties to w:rPr XML
|
|
77
|
-
*/
|
|
78
|
-
function serializeTextFormatting(formatting) {
|
|
79
|
-
if (!formatting) return "";
|
|
80
|
-
const parts = [];
|
|
81
|
-
if (formatting.styleId) parts.push(`<w:rStyle w:val="${escapeXml(formatting.styleId)}"/>`);
|
|
82
|
-
if (formatting.fontFamily) {
|
|
83
|
-
const fontAttrs = [];
|
|
84
|
-
if (formatting.fontFamily.ascii) fontAttrs.push(`w:ascii="${escapeXml(formatting.fontFamily.ascii)}"`);
|
|
85
|
-
if (formatting.fontFamily.hAnsi) fontAttrs.push(`w:hAnsi="${escapeXml(formatting.fontFamily.hAnsi)}"`);
|
|
86
|
-
if (formatting.fontFamily.eastAsia) fontAttrs.push(`w:eastAsia="${escapeXml(formatting.fontFamily.eastAsia)}"`);
|
|
87
|
-
if (formatting.fontFamily.cs) fontAttrs.push(`w:cs="${escapeXml(formatting.fontFamily.cs)}"`);
|
|
88
|
-
if (formatting.fontFamily.hint) fontAttrs.push(`w:hint="${escapeXml(formatting.fontFamily.hint)}"`);
|
|
89
|
-
if (formatting.fontFamily.asciiTheme) fontAttrs.push(`w:asciiTheme="${escapeXml(formatting.fontFamily.asciiTheme)}"`);
|
|
90
|
-
if (formatting.fontFamily.hAnsiTheme) fontAttrs.push(`w:hAnsiTheme="${escapeXml(formatting.fontFamily.hAnsiTheme)}"`);
|
|
91
|
-
if (formatting.fontFamily.eastAsiaTheme) fontAttrs.push(`w:eastAsiaTheme="${escapeXml(formatting.fontFamily.eastAsiaTheme)}"`);
|
|
92
|
-
if (formatting.fontFamily.csTheme) fontAttrs.push(`w:cstheme="${escapeXml(formatting.fontFamily.csTheme)}"`);
|
|
93
|
-
if (fontAttrs.length > 0) parts.push(`<w:rFonts ${fontAttrs.join(" ")}/>`);
|
|
94
|
-
}
|
|
95
|
-
if (formatting.bold === true) parts.push("<w:b/>");
|
|
96
|
-
else if (formatting.bold === false) parts.push("<w:b w:val=\"0\"/>");
|
|
97
|
-
if (formatting.boldCs === true) parts.push("<w:bCs/>");
|
|
98
|
-
else if (formatting.boldCs === false) parts.push("<w:bCs w:val=\"0\"/>");
|
|
99
|
-
if (formatting.italic === true) parts.push("<w:i/>");
|
|
100
|
-
else if (formatting.italic === false) parts.push("<w:i w:val=\"0\"/>");
|
|
101
|
-
if (formatting.italicCs === true) parts.push("<w:iCs/>");
|
|
102
|
-
else if (formatting.italicCs === false) parts.push("<w:iCs w:val=\"0\"/>");
|
|
103
|
-
if (formatting.allCaps === true) parts.push("<w:caps/>");
|
|
104
|
-
else if (formatting.allCaps === false) parts.push("<w:caps w:val=\"0\"/>");
|
|
105
|
-
if (formatting.smallCaps === true) parts.push("<w:smallCaps/>");
|
|
106
|
-
else if (formatting.smallCaps === false) parts.push("<w:smallCaps w:val=\"0\"/>");
|
|
107
|
-
if (formatting.strike === true) parts.push("<w:strike/>");
|
|
108
|
-
else if (formatting.strike === false) parts.push("<w:strike w:val=\"0\"/>");
|
|
109
|
-
if (formatting.doubleStrike === true) parts.push("<w:dstrike/>");
|
|
110
|
-
else if (formatting.doubleStrike === false) parts.push("<w:dstrike w:val=\"0\"/>");
|
|
111
|
-
if (formatting.outline === true) parts.push("<w:outline/>");
|
|
112
|
-
else if (formatting.outline === false) parts.push("<w:outline w:val=\"0\"/>");
|
|
113
|
-
if (formatting.shadow === true) parts.push("<w:shadow/>");
|
|
114
|
-
else if (formatting.shadow === false) parts.push("<w:shadow w:val=\"0\"/>");
|
|
115
|
-
if (formatting.emboss === true) parts.push("<w:emboss/>");
|
|
116
|
-
else if (formatting.emboss === false) parts.push("<w:emboss w:val=\"0\"/>");
|
|
117
|
-
if (formatting.imprint === true) parts.push("<w:imprint/>");
|
|
118
|
-
else if (formatting.imprint === false) parts.push("<w:imprint w:val=\"0\"/>");
|
|
119
|
-
if (formatting.hidden === true) parts.push("<w:vanish/>");
|
|
120
|
-
else if (formatting.hidden === false) parts.push("<w:vanish w:val=\"0\"/>");
|
|
121
|
-
const colorXml = serializeColorElement(formatting.color);
|
|
122
|
-
if (colorXml) parts.push(colorXml);
|
|
123
|
-
if (formatting.spacing !== void 0) parts.push(`<w:spacing w:val="${intAttr(formatting.spacing)}"/>`);
|
|
124
|
-
const horizontalScale = roundHorizontalScalePercentForSerialization(formatting.scale);
|
|
125
|
-
if (horizontalScale !== void 0) parts.push(`<w:w w:val="${intAttr(horizontalScale)}"/>`);
|
|
126
|
-
if (formatting.kerning !== void 0) parts.push(`<w:kern w:val="${intAttr(formatting.kerning)}"/>`);
|
|
127
|
-
if (formatting.position !== void 0) parts.push(`<w:position w:val="${intAttr(formatting.position)}"/>`);
|
|
128
|
-
if (formatting.fontSize !== void 0) parts.push(`<w:sz w:val="${intAttr(formatting.fontSize)}"/>`);
|
|
129
|
-
if (formatting.fontSizeCs !== void 0) parts.push(`<w:szCs w:val="${intAttr(formatting.fontSizeCs)}"/>`);
|
|
130
|
-
let customHighlightShadingXml = "";
|
|
131
|
-
if (formatting.highlight) {
|
|
132
|
-
if (VALID_HIGHLIGHT_COLORS.has(formatting.highlight)) parts.push(`<w:highlight w:val="${formatting.highlight}"/>`);
|
|
133
|
-
else if (!formatting.shading) {
|
|
134
|
-
const hex = formatting.highlight.replace(/^#/u, "");
|
|
135
|
-
if (/^[0-9a-fA-F]{6}$/u.test(hex)) customHighlightShadingXml = `<w:shd w:val="clear" w:color="auto" w:fill="${hex}"/>`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (formatting.underline) {
|
|
139
|
-
const uAttrs = [`w:val="${formatting.underline.style}"`];
|
|
140
|
-
if (formatting.underline.color) {
|
|
141
|
-
if (formatting.underline.color.rgb && isValidHexColor(formatting.underline.color.rgb)) uAttrs.push(`w:color="${escapeXml(formatting.underline.color.rgb)}"`);
|
|
142
|
-
if (formatting.underline.color.themeColor) uAttrs.push(`w:themeColor="${escapeXml(formatting.underline.color.themeColor)}"`);
|
|
143
|
-
if (formatting.underline.color.themeTint) uAttrs.push(`w:themeTint="${escapeXml(formatting.underline.color.themeTint)}"`);
|
|
144
|
-
if (formatting.underline.color.themeShade) uAttrs.push(`w:themeShade="${escapeXml(formatting.underline.color.themeShade)}"`);
|
|
145
|
-
}
|
|
146
|
-
parts.push(`<w:u ${uAttrs.join(" ")}/>`);
|
|
147
|
-
}
|
|
148
|
-
if (formatting.effect) parts.push(`<w:effect w:val="${formatting.effect}"/>`);
|
|
149
|
-
const shadingXml = serializeShading(formatting.shading) || customHighlightShadingXml;
|
|
150
|
-
if (shadingXml) parts.push(shadingXml);
|
|
151
|
-
if (formatting.vertAlign) parts.push(`<w:vertAlign w:val="${formatting.vertAlign}"/>`);
|
|
152
|
-
if (formatting.rtl === true) parts.push("<w:rtl/>");
|
|
153
|
-
else if (formatting.rtl === false) parts.push("<w:rtl w:val=\"0\"/>");
|
|
154
|
-
if (formatting.cs === true) parts.push("<w:cs/>");
|
|
155
|
-
else if (formatting.cs === false) parts.push("<w:cs w:val=\"0\"/>");
|
|
156
|
-
if (formatting.emphasisMark) parts.push(`<w:em w:val="${formatting.emphasisMark}"/>`);
|
|
157
|
-
if (formatting.language) {
|
|
158
|
-
const languageAttrs = [];
|
|
159
|
-
if (formatting.language.val) languageAttrs.push(`w:val="${escapeXml(formatting.language.val)}"`);
|
|
160
|
-
if (formatting.language.eastAsia) languageAttrs.push(`w:eastAsia="${escapeXml(formatting.language.eastAsia)}"`);
|
|
161
|
-
if (formatting.language.bidi) languageAttrs.push(`w:bidi="${escapeXml(formatting.language.bidi)}"`);
|
|
162
|
-
if (languageAttrs.length > 0) parts.push(`<w:lang ${languageAttrs.join(" ")}/>`);
|
|
163
|
-
}
|
|
164
|
-
if (parts.length === 0) return "";
|
|
165
|
-
return `<w:rPr>${parts.join("")}</w:rPr>`;
|
|
166
|
-
}
|
|
167
40
|
function extractRPrInner(rPrXml) {
|
|
168
41
|
if (!rPrXml.startsWith("<w:rPr>") || !rPrXml.endsWith("</w:rPr>")) return "";
|
|
169
42
|
return rPrXml.slice(7, -8);
|
|
@@ -667,4 +540,4 @@ function createTabRun(formatting) {
|
|
|
667
540
|
};
|
|
668
541
|
}
|
|
669
542
|
//#endregion
|
|
670
|
-
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns
|
|
543
|
+
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { serializeParagraphFormatting } from "./paragraphSerializer.js";
|
|
2
2
|
import { serializePartElement } from "./partNamespaces.js";
|
|
3
|
-
import { serializeTextFormatting } from "./runSerializer.js";
|
|
4
3
|
import { serializeTableCellFormatting, serializeTableFormatting, serializeTableRowFormatting } from "./tableSerializer.js";
|
|
4
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
5
5
|
import { escapeXml } from "./xmlUtils.js";
|
|
6
6
|
//#region src/docx/serializer/stylesSerializer.ts
|
|
7
7
|
const serializeStylesXml = (definitions) => {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
//#region src/docx/serializer/textFormattingSerializer.d.ts
|
|
3
|
+
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
|
+
type ClassifiedShadingField = "color" | "fill" | "pattern";
|
|
5
|
+
type ExhaustiveShadingProperties = ExhaustiveFields<document_d_exports.ShadingProperties, ClassifiedShadingField>;
|
|
6
|
+
type ClassifiedTextFormattingField = "bold" | "boldCs" | "italic" | "italicCs" | "underline" | "strike" | "doubleStrike" | "vertAlign" | "smallCaps" | "allCaps" | "hidden" | "color" | "highlight" | "shading" | "fontSize" | "fontSizeCs" | "fontFamily" | "language" | "spacing" | "position" | "scale" | "kerning" | "effect" | "emphasisMark" | "emboss" | "imprint" | "outline" | "shadow" | "rtl" | "cs" | "styleId";
|
|
7
|
+
type ExhaustiveTextFormatting = ExhaustiveFields<document_d_exports.TextFormatting, ClassifiedTextFormattingField>;
|
|
8
|
+
/**
|
|
9
|
+
* Serialize shading properties (w:shd)
|
|
10
|
+
*/
|
|
11
|
+
declare function serializeShading(shading: ExhaustiveShadingProperties | undefined): string;
|
|
12
|
+
/**
|
|
13
|
+
* Serialize text formatting properties to w:rPr XML
|
|
14
|
+
*/
|
|
15
|
+
declare function serializeTextFormatting(input: ExhaustiveTextFormatting | undefined): string;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { serializeShading, serializeTextFormatting };
|