@stll/folio-core 0.42.0 → 0.44.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/headless.js +6 -5
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/snapshot.js +13 -9
- package/dist/compare/content-alignment.js +16 -1
- package/dist/compare/inline-atoms.js +1 -1
- package/dist/compare/style-resources.js +6 -0
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/controller/layoutPipeline.d.ts +2 -1
- package/dist/controller/layoutPipeline.js +5 -2
- package/dist/controller/layoutSession.d.ts +2 -1
- package/dist/controller/layoutSession.js +1 -0
- package/dist/docx/appVersionNormalization.d.ts +0 -18
- package/dist/docx/blockContentParser.js +10 -1
- package/dist/docx/blockRangeMarkers.d.ts +36 -0
- package/dist/docx/blockRangeMarkers.js +59 -0
- package/dist/docx/bookmarkParser.d.ts +2 -20
- package/dist/docx/bookmarkParser.js +6 -30
- package/dist/docx/borderParser.d.ts +13 -0
- package/dist/docx/borderParser.js +71 -0
- package/dist/docx/builtInStyles.d.ts +165 -0
- package/dist/docx/builtInStyles.js +239 -0
- package/dist/docx/commentIdNormalization.d.ts +10 -0
- package/dist/docx/commentIdNormalization.js +33 -0
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +34 -7
- package/dist/docx/commentReferenceNormalization.d.ts +4 -1
- package/dist/docx/commentReferenceNormalization.js +23 -14
- package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
- package/dist/docx/danglingRelationshipReferences.js +30 -0
- package/dist/docx/defaultParagraphStyle.d.ts +39 -0
- package/dist/docx/defaultParagraphStyle.js +54 -0
- package/dist/docx/documentParser.d.ts +2 -1
- package/dist/docx/documentParser.js +2 -2
- package/dist/docx/drawingUtils.d.ts +8 -1
- package/dist/docx/drawingUtils.js +12 -3
- package/dist/docx/fieldParser.js +3 -5
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +19 -2
- package/dist/docx/groupDrawingParser.js +1 -1
- package/dist/docx/headerFooterRefParser.d.ts +15 -3
- package/dist/docx/headerFooterRefParser.js +51 -14
- package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
- package/dist/docx/headerFooterReferenceNormalization.js +5 -1
- package/dist/docx/hyperlinkParser.js +11 -15
- package/dist/docx/imageParser.d.ts +1 -1
- package/dist/docx/imageParser.js +22 -18
- package/dist/docx/imageRawXml.js +5 -5
- package/dist/docx/markupRangeMarker.d.ts +15 -0
- package/dist/docx/markupRangeMarker.js +44 -0
- package/dist/docx/noteReferenceStyles.d.ts +29 -0
- package/dist/docx/noteReferenceStyles.js +70 -0
- package/dist/docx/numberingParser.js +2 -1
- package/dist/docx/numberingReference.d.ts +21 -0
- package/dist/docx/numberingReference.js +21 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +14 -2
- package/dist/docx/numberingReferenceNormalization.js +51 -9
- package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
- package/dist/docx/paragraphParser.js +69 -101
- package/dist/docx/paragraphPropertySource.js +1 -0
- package/dist/docx/paragraphTraversal.d.ts +37 -1
- package/dist/docx/paragraphTraversal.js +84 -1
- package/dist/docx/parseContext.d.ts +37 -0
- package/dist/docx/parseContext.js +67 -0
- package/dist/docx/parseWarningMessage.d.ts +6 -0
- package/dist/docx/parseWarningMessage.js +44 -0
- package/dist/docx/parser.js +86 -24
- package/dist/docx/relsParser.d.ts +28 -11
- package/dist/docx/relsParser.js +26 -13
- package/dist/docx/revisionIdNormalization.js +81 -7
- package/dist/docx/rezip.js +85 -27
- package/dist/docx/runConsolidator.js +1 -2
- package/dist/docx/runParser.d.ts +8 -1
- package/dist/docx/runParser.js +30 -48
- package/dist/docx/sectionParser.d.ts +2 -1
- package/dist/docx/sectionParser.js +21 -65
- package/dist/docx/serializer/borderSerializer.d.ts +1 -2
- package/dist/docx/serializer/commentSerializer.js +22 -9
- package/dist/docx/serializer/documentSerializer.d.ts +1 -5
- package/dist/docx/serializer/documentSerializer.js +6 -16
- package/dist/docx/serializer/headerFooterSerializer.js +5 -0
- package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
- package/dist/docx/serializer/markupRangeAttributes.js +24 -0
- package/dist/docx/serializer/noteSerializer.js +5 -0
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
- package/dist/docx/serializer/paragraphSerializer.js +29 -35
- package/dist/docx/serializer/runSerializer.js +13 -7
- package/dist/docx/serializer/tableSerializer.js +28 -13
- package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
- package/dist/docx/server/build.js +8 -1
- package/dist/docx/server/createBilingualDocument.js +15 -22
- package/dist/docx/server/extractDocxText.js +3 -4
- package/dist/docx/shadingParser.d.ts +6 -0
- package/dist/docx/shadingParser.js +32 -0
- package/dist/docx/shapeParser.js +3 -3
- package/dist/docx/styleParser.js +15 -89
- package/dist/docx/styleReferenceResolution.d.ts +36 -0
- package/dist/docx/styleReferenceResolution.js +51 -0
- package/dist/docx/tableLook.d.ts +57 -0
- package/dist/docx/tableLook.js +63 -0
- package/dist/docx/tableParser.d.ts +7 -9
- package/dist/docx/tableParser.js +64 -110
- package/dist/docx/textBoxParser.js +4 -4
- package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
- package/dist/docx/trackedMoveRangeNormalization.js +11 -21
- package/dist/docx/transitionalSpelling.d.ts +13 -2
- package/dist/docx/transitionalSpelling.js +23 -1
- package/dist/docx/verbatimCapture.js +4 -11
- package/dist/docx/vmlImageParser.js +2 -2
- package/dist/docx/watermarkParser.js +2 -2
- package/dist/docx/xmlParser.d.ts +22 -32
- package/dist/docx/xmlParser.js +36 -21
- package/dist/index.d.ts +2 -2
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +2 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +9 -6
- package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
- package/dist/internal/paragraphFormattingSerialization.js +26 -6
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
- package/dist/layout-bridge/convert/templatePreviewFlow.d.ts +19 -11
- package/dist/layout-bridge/convert/templatePreviewFlow.js +103 -38
- package/dist/layout-bridge/convert/toFlowBlocks.js +12 -3
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/measureBlocks.js +1 -6
- package/dist/layout-engine/types.d.ts +8 -2
- package/dist/layout-engine/types.js +35 -2
- package/dist/markdown/index.js +1 -1
- package/dist/markdown/internals.d.ts +6 -1
- package/dist/markdown/internals.js +14 -1
- package/dist/markdown/renderBlock.js +35 -21
- package/dist/markdown/renderParagraph.js +14 -5
- package/dist/markdown/renderRuns.js +4 -3
- package/dist/markdown/renderTable.js +4 -3
- package/dist/markdown/trailers.js +41 -7
- package/dist/markdown/types.d.ts +3 -7
- package/dist/prosemirror/attrs/index.js +2 -5
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
- package/dist/prosemirror/commands/index.d.ts +3 -3
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/pageBreak.js +12 -1
- package/dist/prosemirror/commands/paragraph.d.ts +3 -3
- package/dist/prosemirror/commands/paragraph.js +2 -2
- package/dist/prosemirror/commentIdAllocator.js +2 -7
- package/dist/prosemirror/conversion/fromProseDoc.js +131 -41
- package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
- package/dist/prosemirror/conversion/toProseDoc.js +402 -328
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
- package/dist/prosemirror/extensions/features/ListExtension.js +42 -4
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
- package/dist/prosemirror/extensions/types.d.ts +2 -2
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/index.js +3 -3
- package/dist/prosemirror/insertOperations.d.ts +9 -2
- package/dist/prosemirror/insertOperations.js +9 -4
- package/dist/prosemirror/listMarker.js +2 -1
- package/dist/prosemirror/numberedRefFields.js +2 -1
- package/dist/prosemirror/pageBreakRunProjection.d.ts +11 -3
- package/dist/prosemirror/pageBreakRunProjection.js +16 -8
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +159 -0
- package/dist/prosemirror/paragraphFormattingProvenance.js +106 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
- package/dist/prosemirror/plugins/documentStyles.js +11 -1
- package/dist/prosemirror/plugins/index.d.ts +2 -2
- package/dist/prosemirror/plugins/index.js +2 -2
- package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
- package/dist/prosemirror/plugins/revisionIds.js +21 -6
- package/dist/prosemirror/plugins/templatePreviewValues.d.ts +42 -1
- package/dist/prosemirror/plugins/templatePreviewValues.js +217 -14
- package/dist/prosemirror/runFormattingReconciliation.js +3 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +31 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +4 -1
- package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
- package/dist/prosemirror/styles/styleResolver.js +15 -6
- package/dist/prosemirror/utils/visualLineNavigation.d.ts +22 -2
- package/dist/prosemirror/utils/visualLineNavigation.js +80 -63
- package/dist/style-engine/styleEngine.d.ts +4 -1
- package/dist/style-engine/styleEngine.js +3 -0
- package/dist/style-sets/extract.js +35 -11
- package/dist/style-sets/stellaStyle.js +46 -39
- package/dist/style-sets/styleSetNormalization.d.ts +19 -0
- package/dist/style-sets/styleSetNormalization.js +99 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +145 -20
- package/dist/utils/headingCollector.d.ts +8 -5
- package/dist/utils/headingCollector.js +23 -25
- package/dist/utils/tableOfContentsStyle.js +9 -2
- package/package.json +3 -2
- package/dist/docx/textWhitespace.d.ts +0 -4
- package/dist/docx/textWhitespace.js +0 -4
- package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
- package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
- package/dist/markdown/headings.d.ts +0 -13
- package/dist/markdown/headings.js +0 -20
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import { isValidHexColor } from "../utils/colorResolver.js";
|
|
2
1
|
import { isValidHexId } from "../utils/hexId.js";
|
|
3
2
|
import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
|
|
3
|
+
import { parseBorderSpec } from "./borderParser.js";
|
|
4
4
|
import { parseFieldType } from "./fieldParser.js";
|
|
5
5
|
import { parseHyperlink as parseHyperlink$1, parseHyperlinkChild } from "./hyperlinkParser.js";
|
|
6
|
+
import { parseMarkupRangeMarker, parseMoveBookmarkMarker } from "./markupRangeMarker.js";
|
|
6
7
|
import { markerFormattingFromLevel, numberingLevelHasMarkerSlot } from "./numberingParser.js";
|
|
8
|
+
import { isNumberingReference } from "./numberingReference.js";
|
|
7
9
|
import { paraIdInRange } from "./paraIdRangeNormalization.js";
|
|
8
10
|
import { assignParagraphPropertySource } from "./paragraphPropertySource.js";
|
|
9
|
-
import {
|
|
11
|
+
import { FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, TabLeaderSchema, TabStopAlignmentSchema, narrowEnum } from "./parserEnums.js";
|
|
10
12
|
import { consolidateParagraphContent } from "./runConsolidator.js";
|
|
11
13
|
import { parseRun, parseRunProperties } from "./runParser.js";
|
|
12
14
|
import { parseSdtProperties } from "./sdtProperties.js";
|
|
13
15
|
import { parseSectionProperties } from "./sectionParser.js";
|
|
16
|
+
import { parseShading } from "./shadingParser.js";
|
|
14
17
|
import { parsePropertyChangeInfo, parseTrackedChangeInfo } from "./trackedChangeInfo.js";
|
|
15
18
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
16
|
-
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findChild, findChildByNamespaceUri, findChildren, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseNumberingLevelAttribute, parseNumericAttribute, selectAlternateContentBranch } from "./xmlParser.js";
|
|
19
|
+
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findChild, findChildByNamespaceUri, findChildren, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseNumberingLevelAttribute, parseNumericAttribute, parseOnOffAttribute, selectAlternateContentBranch } from "./xmlParser.js";
|
|
17
20
|
import { panic } from "better-result";
|
|
18
|
-
import { PARAGRAPH_MARK_CHANGE_KINDS, REVIEW_CARRIERS } from "@stll/docx-core/model";
|
|
21
|
+
import { BIDI_CONTROLS, PARAGRAPH_MARK_CHANGE_KINDS, REVIEW_CARRIERS } from "@stll/docx-core/model";
|
|
19
22
|
//#region src/docx/paragraphParser.ts
|
|
20
23
|
const FOLIO_REVIEW_HISTORY_NAMESPACES = /* @__PURE__ */ new Set(["urn:stella:folio:review-history:1"]);
|
|
21
24
|
/**
|
|
@@ -35,63 +38,6 @@ function extractMathText(el) {
|
|
|
35
38
|
return text;
|
|
36
39
|
}
|
|
37
40
|
/**
|
|
38
|
-
* Parse color value from attributes
|
|
39
|
-
*/
|
|
40
|
-
function parseColorValue(rgb, themeColor, themeTint, themeShade) {
|
|
41
|
-
const color = {};
|
|
42
|
-
if (rgb && rgb !== "auto") color.rgb = rgb;
|
|
43
|
-
else if (rgb === "auto") color.auto = true;
|
|
44
|
-
const validatedThemeColor = narrowEnum(themeColor, ThemeColorSlotSchema);
|
|
45
|
-
if (validatedThemeColor) color.themeColor = validatedThemeColor;
|
|
46
|
-
if (themeTint) color.themeTint = themeTint;
|
|
47
|
-
if (themeShade) color.themeShade = themeShade;
|
|
48
|
-
return color;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Parse shading properties (w:shd)
|
|
52
|
-
*/
|
|
53
|
-
function parseShadingProperties(shd) {
|
|
54
|
-
if (!shd) return;
|
|
55
|
-
const props = {};
|
|
56
|
-
const color = getAttribute(shd, "w", "color");
|
|
57
|
-
if (color && color !== "auto" && isValidHexColor(color)) props.color = { rgb: color };
|
|
58
|
-
const fill = getAttribute(shd, "w", "fill");
|
|
59
|
-
if (fill && fill !== "auto" && isValidHexColor(fill)) props.fill = { rgb: fill };
|
|
60
|
-
const validatedThemeFill = narrowEnum(getAttribute(shd, "w", "themeFill"), ThemeColorSlotSchema);
|
|
61
|
-
if (validatedThemeFill) {
|
|
62
|
-
props.fill = props.fill || {};
|
|
63
|
-
props.fill.themeColor = validatedThemeFill;
|
|
64
|
-
}
|
|
65
|
-
const themeFillTint = getAttribute(shd, "w", "themeFillTint");
|
|
66
|
-
if (themeFillTint && props.fill) props.fill.themeTint = themeFillTint;
|
|
67
|
-
const themeFillShade = getAttribute(shd, "w", "themeFillShade");
|
|
68
|
-
if (themeFillShade && props.fill) props.fill.themeShade = themeFillShade;
|
|
69
|
-
const pattern = narrowEnum(getAttribute(shd, "w", "val"), ShadingPatternSchema);
|
|
70
|
-
if (pattern) props.pattern = pattern;
|
|
71
|
-
return Object.keys(props).length > 0 ? props : void 0;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Parse border specification (w:top, w:bottom, w:left, w:right, etc.)
|
|
75
|
-
*/
|
|
76
|
-
function parseBorderSpec(border) {
|
|
77
|
-
if (!border) return;
|
|
78
|
-
const rawStyle = getAttribute(border, "w", "val");
|
|
79
|
-
if (!rawStyle) return;
|
|
80
|
-
const spec = { style: narrowEnum(rawStyle, BorderStyleSchema) ?? rawStyle };
|
|
81
|
-
const colorVal = getAttribute(border, "w", "color");
|
|
82
|
-
const themeColor = getAttribute(border, "w", "themeColor");
|
|
83
|
-
if (colorVal || themeColor) spec.color = parseColorValue(colorVal, themeColor, getAttribute(border, "w", "themeTint"), getAttribute(border, "w", "themeShade"));
|
|
84
|
-
const sz = parseNumericAttribute(border, "w", "sz");
|
|
85
|
-
if (sz !== void 0) spec.size = sz;
|
|
86
|
-
const space = parseNumericAttribute(border, "w", "space");
|
|
87
|
-
if (space !== void 0) spec.space = space;
|
|
88
|
-
const shadowAttr = getAttribute(border, "w", "shadow");
|
|
89
|
-
if (shadowAttr) spec.shadow = shadowAttr === "1" || shadowAttr === "true";
|
|
90
|
-
const frame = getAttribute(border, "w", "frame");
|
|
91
|
-
if (frame) spec.frame = frame === "1" || frame === "true";
|
|
92
|
-
return spec;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
41
|
* Parse tab stops (w:tabs)
|
|
96
42
|
*/
|
|
97
43
|
function parseTabStops(tabs) {
|
|
@@ -272,10 +218,10 @@ function parseParagraphProperties(pPr, theme, styles) {
|
|
|
272
218
|
if (spacingExplicit.before || spacingExplicit.after) formatting.spacingExplicit = spacingExplicit;
|
|
273
219
|
const lineRule = narrowEnum(getAttribute(spacing, "w", "lineRule"), LineSpacingRuleSchema);
|
|
274
220
|
if (lineRule) formatting.lineSpacingRule = lineRule;
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
221
|
+
const beforeAutospacing = parseOnOffAttribute(spacing, "w", "beforeAutospacing");
|
|
222
|
+
if (beforeAutospacing !== void 0) formatting.beforeAutospacing = beforeAutospacing;
|
|
223
|
+
const afterAutospacing = parseOnOffAttribute(spacing, "w", "afterAutospacing");
|
|
224
|
+
if (afterAutospacing !== void 0) formatting.afterAutospacing = afterAutospacing;
|
|
279
225
|
}
|
|
280
226
|
const ind = propertyChildren.ind;
|
|
281
227
|
if (ind) {
|
|
@@ -314,7 +260,7 @@ function parseParagraphProperties(pPr, theme, styles) {
|
|
|
314
260
|
}
|
|
315
261
|
const shd = propertyChildren.shd;
|
|
316
262
|
if (shd) {
|
|
317
|
-
const shadingResult =
|
|
263
|
+
const shadingResult = parseShading(shd);
|
|
318
264
|
if (shadingResult !== void 0) formatting.shading = shadingResult;
|
|
319
265
|
}
|
|
320
266
|
const tabs = propertyChildren.tabs;
|
|
@@ -347,6 +293,8 @@ function parseParagraphProperties(pPr, theme, styles) {
|
|
|
347
293
|
if (val !== void 0) formatting.numPr.ilvl = val;
|
|
348
294
|
}
|
|
349
295
|
}
|
|
296
|
+
const numberingChange = findChild(numPr, "w", "numberingChange");
|
|
297
|
+
if (numberingChange) formatting.numberingChangeXml = captureVerbatimXml(numberingChange);
|
|
350
298
|
}
|
|
351
299
|
const outlineLvl = propertyChildren.outlineLvl;
|
|
352
300
|
if (outlineLvl) {
|
|
@@ -652,6 +600,27 @@ const hyperlinkRevisionWrapperType = (node) => {
|
|
|
652
600
|
default: return;
|
|
653
601
|
}
|
|
654
602
|
};
|
|
603
|
+
const OMML_NAMESPACE = "http://schemas.openxmlformats.org/officeDocument/2006/math";
|
|
604
|
+
/**
|
|
605
|
+
* A bare OMML element as an inline equation, or nothing when the child is not one.
|
|
606
|
+
*
|
|
607
|
+
* `m:oMath` and `m:oMathPara` have branches of their own. This is for the rest
|
|
608
|
+
* of `m:EG_OMathMathElements` — `m:f`, `m:acc`, `m:rad` and their siblings —
|
|
609
|
+
* which the schema admits wherever `m:oMath` is admitted. They carry no
|
|
610
|
+
* structure the editable model holds, so they travel as the markup they
|
|
611
|
+
* arrived as, exactly like the equations that do have a wrapper.
|
|
612
|
+
*/
|
|
613
|
+
const mathContentOf = (child) => {
|
|
614
|
+
if (getNamespaceUri(child) !== OMML_NAMESPACE) return;
|
|
615
|
+
const equation = {
|
|
616
|
+
type: "mathEquation",
|
|
617
|
+
display: "inline",
|
|
618
|
+
ommlXml: captureVerbatimXml(child)
|
|
619
|
+
};
|
|
620
|
+
const plainText = extractMathText(child);
|
|
621
|
+
if (plainText) equation.plainText = plainText;
|
|
622
|
+
return equation;
|
|
623
|
+
};
|
|
655
624
|
const isHyperlinkChildContent = (content) => content.type === "run" || content.type === "bookmarkStart" || content.type === "bookmarkEnd";
|
|
656
625
|
/**
|
|
657
626
|
* A `w:hyperlink` as paragraph content, with any revision wrapper it holds
|
|
@@ -741,10 +710,8 @@ function parseSimpleField(node, styles, theme, rels, media, rootXmlns = {}) {
|
|
|
741
710
|
fieldType: parseFieldType(instruction),
|
|
742
711
|
content: []
|
|
743
712
|
};
|
|
744
|
-
|
|
745
|
-
if (
|
|
746
|
-
const dirty = getAttribute(node, "w", "dirty");
|
|
747
|
-
if (dirty === "1" || dirty === "true") field.dirty = true;
|
|
713
|
+
if (parseOnOffAttribute(node, "w", "fldLock") === true) field.fldLock = true;
|
|
714
|
+
if (parseOnOffAttribute(node, "w", "dirty") === true) field.dirty = true;
|
|
748
715
|
const inScopeXmlns = mergeXmlnsDeclarations(rootXmlns, node);
|
|
749
716
|
const children = getChildElements(node);
|
|
750
717
|
for (const child of children) {
|
|
@@ -985,57 +952,53 @@ function parseParagraphContents(paraElement, styles, theme, _numbering, rels, me
|
|
|
985
952
|
contents.push(...inner);
|
|
986
953
|
break;
|
|
987
954
|
}
|
|
988
|
-
case "moveFromRangeStart":
|
|
989
|
-
const id = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
990
|
-
const name = getAttribute(child, "w", "name") ?? "";
|
|
955
|
+
case "moveFromRangeStart":
|
|
991
956
|
contents.push({
|
|
992
957
|
type: "moveFromRangeStart",
|
|
993
|
-
|
|
994
|
-
name
|
|
958
|
+
...parseMoveBookmarkMarker(child)
|
|
995
959
|
});
|
|
996
960
|
break;
|
|
997
|
-
|
|
998
|
-
case "moveFromRangeEnd": {
|
|
999
|
-
const id = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
961
|
+
case "moveFromRangeEnd":
|
|
1000
962
|
contents.push({
|
|
1001
963
|
type: "moveFromRangeEnd",
|
|
1002
|
-
|
|
964
|
+
...parseMarkupRangeMarker(child)
|
|
1003
965
|
});
|
|
1004
966
|
break;
|
|
1005
|
-
|
|
1006
|
-
case "moveToRangeStart": {
|
|
1007
|
-
const id = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
1008
|
-
const name = getAttribute(child, "w", "name") ?? "";
|
|
967
|
+
case "moveToRangeStart":
|
|
1009
968
|
contents.push({
|
|
1010
969
|
type: "moveToRangeStart",
|
|
1011
|
-
|
|
1012
|
-
name
|
|
970
|
+
...parseMoveBookmarkMarker(child)
|
|
1013
971
|
});
|
|
1014
972
|
break;
|
|
1015
|
-
|
|
1016
|
-
case "moveToRangeEnd": {
|
|
1017
|
-
const id = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
973
|
+
case "moveToRangeEnd":
|
|
1018
974
|
contents.push({
|
|
1019
975
|
type: "moveToRangeEnd",
|
|
1020
|
-
|
|
976
|
+
...parseMarkupRangeMarker(child)
|
|
1021
977
|
});
|
|
1022
978
|
break;
|
|
1023
|
-
|
|
1024
|
-
case "commentRangeStart": {
|
|
1025
|
-
const commentId = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
979
|
+
case "commentRangeStart":
|
|
1026
980
|
contents.push({
|
|
1027
981
|
type: "commentRangeStart",
|
|
1028
|
-
|
|
982
|
+
...parseMarkupRangeMarker(child)
|
|
1029
983
|
});
|
|
1030
984
|
break;
|
|
1031
|
-
|
|
1032
|
-
case "commentRangeEnd": {
|
|
1033
|
-
const commentId = Number.parseInt(getAttribute(child, "w", "id") ?? "0", 10);
|
|
985
|
+
case "commentRangeEnd":
|
|
1034
986
|
contents.push({
|
|
1035
987
|
type: "commentRangeEnd",
|
|
1036
|
-
|
|
988
|
+
...parseMarkupRangeMarker(child)
|
|
1037
989
|
});
|
|
1038
990
|
break;
|
|
991
|
+
case "bdo":
|
|
992
|
+
case "dir": {
|
|
993
|
+
const direction = getAttribute(child, "w", "val");
|
|
994
|
+
const wrapper = {
|
|
995
|
+
type: "bidiWrapper",
|
|
996
|
+
control: localName === "bdo" ? BIDI_CONTROLS.override : BIDI_CONTROLS.embedding,
|
|
997
|
+
content: parseParagraphContents(child, styles, theme, null, rels, media, trackedContext, inScopeXmlns)
|
|
998
|
+
};
|
|
999
|
+
if (direction === "ltr" || direction === "rtl") wrapper.direction = direction;
|
|
1000
|
+
contents.push(wrapper);
|
|
1001
|
+
break;
|
|
1039
1002
|
}
|
|
1040
1003
|
case "oMath":
|
|
1041
1004
|
case "oMathPara": {
|
|
@@ -1051,7 +1014,11 @@ function parseParagraphContents(paraElement, styles, theme, _numbering, rels, me
|
|
|
1051
1014
|
contents.push(mathEq);
|
|
1052
1015
|
break;
|
|
1053
1016
|
}
|
|
1054
|
-
default:
|
|
1017
|
+
default: {
|
|
1018
|
+
const mathElement = mathContentOf(child);
|
|
1019
|
+
if (mathElement !== void 0) contents.push(mathElement);
|
|
1020
|
+
break;
|
|
1021
|
+
}
|
|
1055
1022
|
}
|
|
1056
1023
|
}
|
|
1057
1024
|
if (inComplexField && afterSeparator) contents.push(...complexFieldResultRuns);
|
|
@@ -1114,7 +1081,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
1114
1081
|
}
|
|
1115
1082
|
if (effectiveNumPr && numbering) {
|
|
1116
1083
|
const { numId, ilvl = 0 } = effectiveNumPr;
|
|
1117
|
-
if (numId
|
|
1084
|
+
if (isNumberingReference(numId)) {
|
|
1118
1085
|
const level = numbering.getLevel(numId, ilvl);
|
|
1119
1086
|
if (level) {
|
|
1120
1087
|
const levelNumFmts = [];
|
|
@@ -1269,7 +1236,8 @@ const getParagraphContentText = (content) => {
|
|
|
1269
1236
|
case "complexField": return content.fieldResult.map(getRunText).join("");
|
|
1270
1237
|
case "inlineSdt": return content.content.map(getParagraphContentText).join("");
|
|
1271
1238
|
case "insertion":
|
|
1272
|
-
case "moveTo":
|
|
1239
|
+
case "moveTo":
|
|
1240
|
+
case "bidiWrapper": return content.content.map(getParagraphContentText).join("");
|
|
1273
1241
|
case "deletion":
|
|
1274
1242
|
case "moveFrom": return "";
|
|
1275
1243
|
case "mathEquation": return content.plainText ?? "";
|
|
@@ -1310,7 +1278,7 @@ function isEmptyParagraph(paragraph) {
|
|
|
1310
1278
|
* @returns true if paragraph has numbering properties
|
|
1311
1279
|
*/
|
|
1312
1280
|
function isListItem(paragraph) {
|
|
1313
|
-
return paragraph.formatting?.numPr
|
|
1281
|
+
return isNumberingReference(paragraph.formatting?.numPr?.numId);
|
|
1314
1282
|
}
|
|
1315
1283
|
/**
|
|
1316
1284
|
* Get the list level of a paragraph (0-8)
|
|
@@ -9,6 +9,42 @@ type DocxParagraphSurfaces = {
|
|
|
9
9
|
};
|
|
10
10
|
/** Visit every run directly owned by a paragraph's inline-content tree. */
|
|
11
11
|
declare const visitParagraphRuns: (paragraph: document_d_exports.Paragraph, visit: (run: document_d_exports.Run) => void) => void;
|
|
12
|
+
/**
|
|
13
|
+
* One position in an inline-content array: the array itself, the index, and
|
|
14
|
+
* what sits there. A normaliser that drops or rewrites a marker needs the
|
|
15
|
+
* array and the index, not only the value.
|
|
16
|
+
*/
|
|
17
|
+
type InlineContentSlot = {
|
|
18
|
+
content: document_d_exports.ParagraphContent[];
|
|
19
|
+
index: number;
|
|
20
|
+
item: document_d_exports.ParagraphContent;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Visit every inline-content position a paragraph owns, in document order,
|
|
24
|
+
* descending through every wrapper that is transparent to a range marker.
|
|
25
|
+
*
|
|
26
|
+
* The model validator walks the whole inline tree; a normaliser that walks
|
|
27
|
+
* only `paragraph.content` sees a different document from the one the
|
|
28
|
+
* validator judges, and a marker inside `w:ins`, `w:hyperlink`, `w:sdt`,
|
|
29
|
+
* `w:bdo` or `w:dir` then reaches the validator unnormalised. Both sides read
|
|
30
|
+
* the tree through this one traversal so they cannot disagree again.
|
|
31
|
+
*
|
|
32
|
+
* A complex field's runs are skipped: `fieldCode` and `fieldResult` hold runs
|
|
33
|
+
* only, and a run is not a marker position.
|
|
34
|
+
*/
|
|
35
|
+
declare const visitInlineContentSlots: (paragraph: document_d_exports.Paragraph, visit: (slot: InlineContentSlot) => void) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Positions marked for removal, per inline-content array.
|
|
38
|
+
*
|
|
39
|
+
* Removal shifts every later index in that array, so a normaliser records the
|
|
40
|
+
* positions while it reads and drops them once, after it has finished reading.
|
|
41
|
+
*/
|
|
42
|
+
declare class InlineContentRemovals {
|
|
43
|
+
#private;
|
|
44
|
+
mark({ content, index }: Pick<InlineContentSlot, "content" | "index">): void;
|
|
45
|
+
/** Applies every marked removal and answers how many items were dropped. */
|
|
46
|
+
apply(): number;
|
|
47
|
+
}
|
|
12
48
|
declare const visitDocxParagraphs: ({ documentBody, headers, footers, footnotes, endnotes }: DocxParagraphSurfaces, visit: (paragraph: document_d_exports.Paragraph) => void) => void;
|
|
13
49
|
//#endregion
|
|
14
|
-
export { DocxParagraphSurfaces, visitDocxParagraphs, visitParagraphRuns };
|
|
50
|
+
export { DocxParagraphSurfaces, InlineContentRemovals, InlineContentSlot, visitDocxParagraphs, visitInlineContentSlots, visitParagraphRuns };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { panic } from "better-result";
|
|
1
2
|
//#region src/docx/paragraphTraversal.ts
|
|
2
3
|
/** Visit every run directly owned by a paragraph's inline-content tree. */
|
|
3
4
|
const visitParagraphRuns = (paragraph, visit) => {
|
|
@@ -15,6 +16,7 @@ const visitParagraphRuns = (paragraph, visit) => {
|
|
|
15
16
|
case "moveFrom":
|
|
16
17
|
case "moveTo":
|
|
17
18
|
case "inlineSdt":
|
|
19
|
+
case "bidiWrapper":
|
|
18
20
|
for (const child of content.content) visitParagraphContent(child);
|
|
19
21
|
return;
|
|
20
22
|
case "complexField":
|
|
@@ -36,6 +38,87 @@ const visitParagraphRuns = (paragraph, visit) => {
|
|
|
36
38
|
};
|
|
37
39
|
for (const content of paragraph.content) visitParagraphContent(content);
|
|
38
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Visit every inline-content position a paragraph owns, in document order,
|
|
43
|
+
* descending through every wrapper that is transparent to a range marker.
|
|
44
|
+
*
|
|
45
|
+
* The model validator walks the whole inline tree; a normaliser that walks
|
|
46
|
+
* only `paragraph.content` sees a different document from the one the
|
|
47
|
+
* validator judges, and a marker inside `w:ins`, `w:hyperlink`, `w:sdt`,
|
|
48
|
+
* `w:bdo` or `w:dir` then reaches the validator unnormalised. Both sides read
|
|
49
|
+
* the tree through this one traversal so they cannot disagree again.
|
|
50
|
+
*
|
|
51
|
+
* A complex field's runs are skipped: `fieldCode` and `fieldResult` hold runs
|
|
52
|
+
* only, and a run is not a marker position.
|
|
53
|
+
*/
|
|
54
|
+
const visitInlineContentSlots = (paragraph, visit) => {
|
|
55
|
+
const visitContent = (content) => {
|
|
56
|
+
for (const [index, item] of content.entries()) {
|
|
57
|
+
visit({
|
|
58
|
+
content,
|
|
59
|
+
index,
|
|
60
|
+
item
|
|
61
|
+
});
|
|
62
|
+
switch (item.type) {
|
|
63
|
+
case "hyperlink":
|
|
64
|
+
visitContent(item.children);
|
|
65
|
+
break;
|
|
66
|
+
case "simpleField":
|
|
67
|
+
case "inlineSdt":
|
|
68
|
+
case "insertion":
|
|
69
|
+
case "deletion":
|
|
70
|
+
case "moveFrom":
|
|
71
|
+
case "moveTo":
|
|
72
|
+
case "bidiWrapper":
|
|
73
|
+
visitContent(item.content);
|
|
74
|
+
break;
|
|
75
|
+
case "run":
|
|
76
|
+
case "complexField":
|
|
77
|
+
case "bookmarkStart":
|
|
78
|
+
case "bookmarkEnd":
|
|
79
|
+
case "commentRangeStart":
|
|
80
|
+
case "commentRangeEnd":
|
|
81
|
+
case "commentReference":
|
|
82
|
+
case "moveFromRangeStart":
|
|
83
|
+
case "moveFromRangeEnd":
|
|
84
|
+
case "moveToRangeStart":
|
|
85
|
+
case "moveToRangeEnd":
|
|
86
|
+
case "mathEquation": break;
|
|
87
|
+
default: panic(`Unsupported paragraph content: ${JSON.stringify(item)}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
visitContent(paragraph.content);
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Positions marked for removal, per inline-content array.
|
|
95
|
+
*
|
|
96
|
+
* Removal shifts every later index in that array, so a normaliser records the
|
|
97
|
+
* positions while it reads and drops them once, after it has finished reading.
|
|
98
|
+
*/
|
|
99
|
+
var InlineContentRemovals = class {
|
|
100
|
+
#byContent = /* @__PURE__ */ new Map();
|
|
101
|
+
mark({ content, index }) {
|
|
102
|
+
const indexes = this.#byContent.get(content);
|
|
103
|
+
if (indexes) {
|
|
104
|
+
indexes.add(index);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.#byContent.set(content, /* @__PURE__ */ new Set([index]));
|
|
108
|
+
}
|
|
109
|
+
/** Applies every marked removal and answers how many items were dropped. */
|
|
110
|
+
apply() {
|
|
111
|
+
let removed = 0;
|
|
112
|
+
for (const [content, indexes] of this.#byContent) {
|
|
113
|
+
if (indexes.size === 0) continue;
|
|
114
|
+
const next = content.filter((_, index) => !indexes.has(index));
|
|
115
|
+
removed += content.length - next.length;
|
|
116
|
+
content.length = 0;
|
|
117
|
+
content.push(...next);
|
|
118
|
+
}
|
|
119
|
+
return removed;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
39
122
|
const visitDocxParagraphs = ({ documentBody, headers, footers, footnotes, endnotes }, visit) => {
|
|
40
123
|
const seenParagraphs = /* @__PURE__ */ new WeakSet();
|
|
41
124
|
const visitParagraph = (paragraph) => {
|
|
@@ -76,4 +159,4 @@ const visitDocxParagraphs = ({ documentBody, headers, footers, footnotes, endnot
|
|
|
76
159
|
for (const comment of documentBody.comments ?? []) for (const paragraph of comment.content) visitParagraph(paragraph);
|
|
77
160
|
};
|
|
78
161
|
//#endregion
|
|
79
|
-
export { visitDocxParagraphs, visitParagraphRuns };
|
|
162
|
+
export { InlineContentRemovals, visitDocxParagraphs, visitInlineContentSlots, visitParagraphRuns };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ParseWarning, ParseWarningCode } from "@stll/docx-core/model";
|
|
2
|
+
//#region src/docx/parseContext.d.ts
|
|
3
|
+
/** What a call site states; the collector supplies the rest. */
|
|
4
|
+
type ParseWarningReport = {
|
|
5
|
+
code: ParseWarningCode;
|
|
6
|
+
/** The element as written, prefix included. */
|
|
7
|
+
element?: string;
|
|
8
|
+
/** The best position this part can name, e.g. `style "Heading1"`. */
|
|
9
|
+
at?: string;
|
|
10
|
+
/** The value folio declined to read, as written. */
|
|
11
|
+
value?: string;
|
|
12
|
+
/** Text passed through from another owner, for the pass-through codes. */
|
|
13
|
+
detail?: string;
|
|
14
|
+
/** How many occurrences this one report stands for; defaults to 1. */
|
|
15
|
+
count?: number;
|
|
16
|
+
};
|
|
17
|
+
type ParseContext = {
|
|
18
|
+
/** Record one normalisation applied to input folio accepted. */
|
|
19
|
+
warn: (report: ParseWarningReport) => void;
|
|
20
|
+
/** The same collector, reporting against another part or position. */
|
|
21
|
+
scoped: (location: {
|
|
22
|
+
part?: string;
|
|
23
|
+
at?: string;
|
|
24
|
+
}) => ParseContext;
|
|
25
|
+
};
|
|
26
|
+
type ParseWarningCollector = {
|
|
27
|
+
context: ParseContext;
|
|
28
|
+
/**
|
|
29
|
+
* Everything recorded, in the order it was recorded, followed by one entry
|
|
30
|
+
* per code whose occurrences ran past the cap. Deterministic: the same
|
|
31
|
+
* document yields the same list.
|
|
32
|
+
*/
|
|
33
|
+
warnings: () => ParseWarning[];
|
|
34
|
+
};
|
|
35
|
+
declare const createParseWarningCollector: (part?: string) => ParseWarningCollector;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ParseContext, ParseWarningCollector, ParseWarningReport, createParseWarningCollector };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { MAX_RETAINED_PARSE_WARNINGS_PER_CODE } from "@stll/docx-core/model";
|
|
2
|
+
//#region src/docx/parseContext.ts
|
|
3
|
+
/**
|
|
4
|
+
* The channel a parser reports a normalisation through.
|
|
5
|
+
*
|
|
6
|
+
* Folio accepts input Word accepts, which means normalising at the parse
|
|
7
|
+
* boundary rather than refusing. Every such decision has to be visible, and
|
|
8
|
+
* before this the only place that could say so was `parseDocx` itself: the
|
|
9
|
+
* leaf readers are pure functions with no way to report, so a value outside
|
|
10
|
+
* `ST_OnOff` or a `w:type` outside `ST_HdrFtr` was normalised in silence.
|
|
11
|
+
*
|
|
12
|
+
* The context is an explicit parameter, never a module-level accumulator and
|
|
13
|
+
* never async-local storage. Parsers stay re-entrant, a test can hand one in
|
|
14
|
+
* and read what a single reader reported, and two documents parsed at once
|
|
15
|
+
* cannot write into each other's list. The cost is a threaded argument, which
|
|
16
|
+
* is also the thing that makes the reporting greppable.
|
|
17
|
+
*/
|
|
18
|
+
const PACKAGE_PART = "package";
|
|
19
|
+
const createParseWarningCollector = (part = PACKAGE_PART) => {
|
|
20
|
+
const retained = [];
|
|
21
|
+
const retainedByCode = /* @__PURE__ */ new Map();
|
|
22
|
+
const suppressedByCode = /* @__PURE__ */ new Map();
|
|
23
|
+
const record = (location, report) => {
|
|
24
|
+
const count = report.count ?? 1;
|
|
25
|
+
const kept = retainedByCode.get(report.code) ?? 0;
|
|
26
|
+
if (kept >= MAX_RETAINED_PARSE_WARNINGS_PER_CODE) {
|
|
27
|
+
suppressedByCode.set(report.code, (suppressedByCode.get(report.code) ?? 0) + count);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
retainedByCode.set(report.code, kept + 1);
|
|
31
|
+
retained.push({
|
|
32
|
+
code: report.code,
|
|
33
|
+
location: {
|
|
34
|
+
...location,
|
|
35
|
+
...report.element === void 0 ? {} : { element: report.element },
|
|
36
|
+
...report.at === void 0 ? {} : { at: report.at }
|
|
37
|
+
},
|
|
38
|
+
...report.value === void 0 ? {} : { value: report.value },
|
|
39
|
+
...report.detail === void 0 ? {} : { detail: report.detail },
|
|
40
|
+
count
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const contextAt = (location) => ({
|
|
44
|
+
warn: (report) => {
|
|
45
|
+
record(location, report);
|
|
46
|
+
},
|
|
47
|
+
scoped: (next) => {
|
|
48
|
+
const at = next.at ?? location.at;
|
|
49
|
+
return contextAt({
|
|
50
|
+
part: next.part ?? location.part,
|
|
51
|
+
...location.element === void 0 ? {} : { element: location.element },
|
|
52
|
+
...at === void 0 ? {} : { at }
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
context: contextAt({ part }),
|
|
58
|
+
warnings: () => [...retained, ...[...suppressedByCode.entries()].sort(([left], [right]) => left < right ? -1 : 1).map(([code, count]) => ({
|
|
59
|
+
code,
|
|
60
|
+
location: { part },
|
|
61
|
+
count,
|
|
62
|
+
detail: `${String(count)} further occurrence(s) were counted but not retained.`
|
|
63
|
+
}))]
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
//#endregion
|
|
67
|
+
export { createParseWarningCollector };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ParseWarning } from "@stll/docx-core/model";
|
|
2
|
+
//#region src/docx/parseWarningMessage.d.ts
|
|
3
|
+
declare const formatParseWarning: (warning: ParseWarning) => string;
|
|
4
|
+
declare const formatParseWarnings: (warnings: readonly ParseWarning[]) => string[];
|
|
5
|
+
//#endregion
|
|
6
|
+
export { formatParseWarning, formatParseWarnings };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
|
|
2
|
+
//#region src/docx/parseWarningMessage.ts
|
|
3
|
+
/**
|
|
4
|
+
* The one place a parse warning becomes a sentence.
|
|
5
|
+
*
|
|
6
|
+
* `Document.warnings` is the string list hosts have always read, and it is now
|
|
7
|
+
* rendered from `Document.parseWarnings` rather than written at the call site,
|
|
8
|
+
* so a warning cannot say one thing in the structured list and another in the
|
|
9
|
+
* prose. The map is total over the code union: a new code does not compile
|
|
10
|
+
* until it has a message.
|
|
11
|
+
*/
|
|
12
|
+
const plural = (count, singular, pluralForm = `${singular}s`) => `${String(count)} ${count === 1 ? singular : pluralForm}`;
|
|
13
|
+
/** The location suffix, omitted when the part is all we know. */
|
|
14
|
+
const where = ({ location }) => {
|
|
15
|
+
if (location.at === void 0) return "";
|
|
16
|
+
return ` at ${location.at} in ${location.part}`;
|
|
17
|
+
};
|
|
18
|
+
const quoted = (value) => value === void 0 ? "" : ` "${value}"`;
|
|
19
|
+
const PARSE_WARNING_MESSAGES = {
|
|
20
|
+
[PARSE_WARNING_CODES.packageDecrypted]: () => "Document was opened from password-protected storage; saving writes an unencrypted .docx file.",
|
|
21
|
+
[PARSE_WARNING_CODES.packageArchive]: (warning) => warning.detail ?? "The archive reader reported an issue.",
|
|
22
|
+
[PARSE_WARNING_CODES.documentPartMissing]: () => "No document.xml found in DOCX",
|
|
23
|
+
[PARSE_WARNING_CODES.documentModelIssue]: (warning) => warning.detail ?? "The document model reported an issue.",
|
|
24
|
+
[PARSE_WARNING_CODES.duplicateCommentId]: (warning) => `Dropped ${plural(warning.count, "comment")} repeating a w:id another comment already defines.`,
|
|
25
|
+
[PARSE_WARNING_CODES.missingCommentId]: (warning) => `Dropped ${plural(warning.count, "comment")} with no readable w:id.`,
|
|
26
|
+
[PARSE_WARNING_CODES.duplicateNoteId]: (warning) => `Dropped ${plural(warning.count, "note")} repeating a w:id another note already defines.`,
|
|
27
|
+
[PARSE_WARNING_CODES.danglingCommentReference]: (warning) => `Removed ${plural(warning.count, "dangling comment reference marker")} whose comments.xml entries are missing.`,
|
|
28
|
+
[PARSE_WARNING_CODES.unbalancedCommentRange]: (warning) => `Re-anchored ${plural(warning.count, "unbalanced comment range marker")} as point comments.`,
|
|
29
|
+
[PARSE_WARNING_CODES.danglingHeaderReference]: (warning) => `Removed ${plural(warning.count, "dangling header reference")} whose header parts are missing.`,
|
|
30
|
+
[PARSE_WARNING_CODES.danglingFooterReference]: (warning) => `Removed ${plural(warning.count, "dangling footer reference")} whose footer parts are missing.`,
|
|
31
|
+
[PARSE_WARNING_CODES.danglingRelationshipId]: (warning) => `Left relationship id${quoted(warning.value)} unresolved${where(warning)}; the part defines no such relationship.`,
|
|
32
|
+
[PARSE_WARNING_CODES.unnumberedParagraph]: (warning) => `Unnumbered ${plural(warning.count, "paragraph")} whose numbering definitions are missing.`,
|
|
33
|
+
[PARSE_WARNING_CODES.unnumberedStyle]: (warning) => `Unnumbered style${quoted(warning.value)} whose numbering definition is missing.`,
|
|
34
|
+
[PARSE_WARNING_CODES.unbalancedMoveRange]: (warning) => `Removed ${plural(warning.count, "unbalanced tracked move range marker")}.`,
|
|
35
|
+
[PARSE_WARNING_CODES.headerFooterTypeOutsideEnum]: (warning) => `Read header/footer type${quoted(warning.value)} as "default"${where(warning)}; ST_HdrFtr is even, default or first.`,
|
|
36
|
+
[PARSE_WARNING_CODES.unrecognisedOnOffValue]: (warning) => `Ignored on/off value${quoted(warning.value)}${where(warning)}; ST_OnOff is 1, 0, true, false, on or off.`,
|
|
37
|
+
[PARSE_WARNING_CODES.borderWithoutValue]: (warning) => `Read a border with no w:val${where(warning)} as having no border style.`,
|
|
38
|
+
[PARSE_WARNING_CODES.styleSetDuplicateStyleId]: (warning) => `Dropped a style repeating the id${quoted(warning.value)} another style in the set already defines.`,
|
|
39
|
+
[PARSE_WARNING_CODES.styleSetInitialStyleMissing]: (warning) => `The style set names initial paragraph style${quoted(warning.value)}, which it does not contain; used the set's default instead${where(warning)}.`
|
|
40
|
+
};
|
|
41
|
+
const formatParseWarning = (warning) => PARSE_WARNING_MESSAGES[warning.code](warning);
|
|
42
|
+
const formatParseWarnings = (warnings) => warnings.map(formatParseWarning);
|
|
43
|
+
//#endregion
|
|
44
|
+
export { formatParseWarning, formatParseWarnings };
|