@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
package/dist/docx/imageParser.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { sanitizeImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
2
2
|
import { emuToPixels } from "../utils/units.js";
|
|
3
3
|
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
4
|
-
import { WRAP_ELEMENT_NAMES, parsePositionH, parsePositionV, parseWrapElement } from "./drawingUtils.js";
|
|
4
|
+
import { WRAP_ELEMENT_NAMES, parseAnchorBehindDoc, parsePositionH, parsePositionV, parseWrapElement } from "./drawingUtils.js";
|
|
5
5
|
import { parseGraphicFrameLocks } from "./graphicFrameLocks.js";
|
|
6
|
-
import {
|
|
6
|
+
import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "./relsParser.js";
|
|
7
7
|
import { isTextBoxDrawing } from "./textBoxParser.js";
|
|
8
8
|
import { findByFullName, findChild, getAttribute, getChildElements, parseNumericAttribute, parseOnOffValue } from "./xmlParser.js";
|
|
9
9
|
//#region src/docx/imageParser.ts
|
|
@@ -178,17 +178,20 @@ function parseImageOpacity(blip) {
|
|
|
178
178
|
return Math.max(0, amt / 1e5);
|
|
179
179
|
}
|
|
180
180
|
/**
|
|
181
|
-
* Extract rId from a:blip element
|
|
181
|
+
* Extract rId from a:blip element.
|
|
182
|
+
*
|
|
183
|
+
* Undefined when the drawing has no blip to read one from: a chart, a diagram
|
|
184
|
+
* or an OLE frame carries an `a:graphic` that is not a picture, and a
|
|
185
|
+
* `wp:inline` may carry no graphic at all.
|
|
182
186
|
*/
|
|
183
187
|
function extractBlipRId(blip) {
|
|
184
|
-
if (!blip) return
|
|
188
|
+
if (!blip) return;
|
|
185
189
|
const rEmbed = getAttribute(blip, "r", "embed");
|
|
186
190
|
if (rEmbed) return rEmbed;
|
|
187
191
|
const embed = getAttribute(blip, null, "embed");
|
|
188
192
|
if (embed) return embed;
|
|
189
193
|
const rLink = getAttribute(blip, "r", "link");
|
|
190
194
|
if (rLink) return rLink;
|
|
191
|
-
return "";
|
|
192
195
|
}
|
|
193
196
|
/**
|
|
194
197
|
* Find transform (a:xfrm) from picture shape properties
|
|
@@ -242,10 +245,9 @@ function getMimeType(path) {
|
|
|
242
245
|
* @returns Object with src (data URL or blob), mimeType, and filename
|
|
243
246
|
*/
|
|
244
247
|
function resolveImageData(rId, rels, media) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const targetPath = rel.target;
|
|
248
|
+
const resolved = resolveRelationshipIdOfType(rels, rId, RELATIONSHIP_TYPES.image);
|
|
249
|
+
if (resolved.status !== "resolved") return {};
|
|
250
|
+
const targetPath = resolved.relationship.target;
|
|
249
251
|
if (!targetPath) return {};
|
|
250
252
|
const normalizedPath = normalizeMediaPath(targetPath);
|
|
251
253
|
const filename = targetPath.split("/").pop();
|
|
@@ -319,7 +321,7 @@ function parseInline(inlineEl, rels, media) {
|
|
|
319
321
|
if (distR !== void 0) wrap.distR = distR;
|
|
320
322
|
const image = {
|
|
321
323
|
type: "image",
|
|
322
|
-
rId,
|
|
324
|
+
...rId === void 0 ? {} : { rId },
|
|
323
325
|
size,
|
|
324
326
|
wrap
|
|
325
327
|
};
|
|
@@ -337,11 +339,12 @@ function parseInline(inlineEl, rels, media) {
|
|
|
337
339
|
if (crop) image.crop = crop;
|
|
338
340
|
if (opacity !== void 0) image.opacity = opacity;
|
|
339
341
|
if (frameLocks) image.frameLocks = frameLocks;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
+
const hlink = resolveRelationshipIdOfType(rels, props.hlinkRId, RELATIONSHIP_TYPES.hyperlink);
|
|
343
|
+
if (hlink.status === "resolved") {
|
|
344
|
+
const safeHref = sanitizeExternalUrl(hlink.relationship.target);
|
|
342
345
|
if (safeHref) {
|
|
343
346
|
image.hlinkHref = safeHref;
|
|
344
|
-
image.hlinkRId =
|
|
347
|
+
image.hlinkRId = hlink.relationship.id;
|
|
345
348
|
}
|
|
346
349
|
}
|
|
347
350
|
return image;
|
|
@@ -359,7 +362,7 @@ function parseAnchor(anchorEl, rels, media) {
|
|
|
359
362
|
const padding = parseEffectExtent(findByFullName(anchorEl, "wp:effectExtent"));
|
|
360
363
|
const props = parseDocProps(findByFullName(anchorEl, "wp:docPr"));
|
|
361
364
|
const frameLocks = parseGraphicFrameLocks(anchorEl);
|
|
362
|
-
const behindDoc =
|
|
365
|
+
const behindDoc = parseAnchorBehindDoc(anchorEl);
|
|
363
366
|
const layoutInCell = parseOnOffAttr(anchorEl, "layoutInCell");
|
|
364
367
|
const allowOverlap = parseOnOffAttr(anchorEl, "allowOverlap");
|
|
365
368
|
const anchorDistT = parseNumericAttribute(anchorEl, null, "distT");
|
|
@@ -391,7 +394,7 @@ function parseAnchor(anchorEl, rels, media) {
|
|
|
391
394
|
const transform = parseTransform(findPictureTransform(anchorEl));
|
|
392
395
|
const image = {
|
|
393
396
|
type: "image",
|
|
394
|
-
rId,
|
|
397
|
+
...rId === void 0 ? {} : { rId },
|
|
395
398
|
size,
|
|
396
399
|
wrap
|
|
397
400
|
};
|
|
@@ -412,11 +415,12 @@ function parseAnchor(anchorEl, rels, media) {
|
|
|
412
415
|
if (frameLocks) image.frameLocks = frameLocks;
|
|
413
416
|
if (layoutInCell !== void 0) image.layoutInCell = layoutInCell;
|
|
414
417
|
if (allowOverlap !== void 0) image.allowOverlap = allowOverlap;
|
|
415
|
-
|
|
416
|
-
|
|
418
|
+
const hlink = resolveRelationshipIdOfType(rels, props.hlinkRId, RELATIONSHIP_TYPES.hyperlink);
|
|
419
|
+
if (hlink.status === "resolved") {
|
|
420
|
+
const safeHref = sanitizeExternalUrl(hlink.relationship.target);
|
|
417
421
|
if (safeHref) {
|
|
418
422
|
image.hlinkHref = safeHref;
|
|
419
|
-
image.hlinkRId =
|
|
423
|
+
image.hlinkRId = hlink.relationship.id;
|
|
420
424
|
}
|
|
421
425
|
}
|
|
422
426
|
return image;
|
package/dist/docx/imageRawXml.js
CHANGED
|
@@ -46,12 +46,12 @@ const DRAWING_SAFETY_CLASSES = {
|
|
|
46
46
|
OPAQUE: "opaque"
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
49
|
+
* A drawing with no picture relationship has no picture to regenerate. The
|
|
50
|
+
* serializer writes the anchor back without a graphic, which is faithful for an
|
|
51
|
+
* anchor that never had one and lossy for a chart or an OLE frame, so the
|
|
52
|
+
* drawing counts as opaque and an edit must block the save.
|
|
53
53
|
*/
|
|
54
|
-
const canRegenerateDrawing = (drawing) => drawing.image.rId !==
|
|
54
|
+
const canRegenerateDrawing = (drawing) => drawing.image.rId !== void 0;
|
|
55
55
|
/**
|
|
56
56
|
* Classify a drawing by what the run serializer will do with it.
|
|
57
57
|
*
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { XmlElement } from "./xmlParser.js";
|
|
3
|
+
//#region src/docx/markupRangeMarker.d.ts
|
|
4
|
+
declare const parseMarkupRangeMarker: (node: XmlElement) => document_d_exports.MarkupRangeMarker;
|
|
5
|
+
declare const parseBookmarkRangeMarker: (node: XmlElement) => document_d_exports.BookmarkRangeMarker;
|
|
6
|
+
/**
|
|
7
|
+
* `w:author` is required on `CT_MoveBookmark`, so an absent one takes the same
|
|
8
|
+
* `Unknown` fallback a tracked change takes rather than leaving the saved
|
|
9
|
+
* package short of an attribute the schema demands. `w:date` is required too,
|
|
10
|
+
* but inventing a timestamp would state a fact about the document that is not
|
|
11
|
+
* true, so an absent date stays absent.
|
|
12
|
+
*/
|
|
13
|
+
declare const parseMoveBookmarkMarker: (node: XmlElement) => document_d_exports.MoveBookmarkMarker;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { parseBookmarkRangeMarker, parseMarkupRangeMarker, parseMoveBookmarkMarker };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getAttribute, parseNumericAttribute } from "./xmlParser.js";
|
|
2
|
+
//#region src/docx/markupRangeMarker.ts
|
|
3
|
+
/** ST_DisplacedByCustomXml. A value outside it is not a placement folio can honour. */
|
|
4
|
+
const DISPLACED_BY_CUSTOM_XML = /* @__PURE__ */ new Set(["next", "prev"]);
|
|
5
|
+
const parseDisplacedByCustomXml = (node) => {
|
|
6
|
+
const value = getAttribute(node, "w", "displacedByCustomXml") ?? "";
|
|
7
|
+
return DISPLACED_BY_CUSTOM_XML.has(value) ? value : void 0;
|
|
8
|
+
};
|
|
9
|
+
const parseMarkupRangeMarker = (node) => {
|
|
10
|
+
const marker = { id: parseNumericAttribute(node, "w", "id") ?? 0 };
|
|
11
|
+
const displacedByCustomXml = parseDisplacedByCustomXml(node);
|
|
12
|
+
if (displacedByCustomXml !== void 0) marker.displacedByCustomXml = displacedByCustomXml;
|
|
13
|
+
return marker;
|
|
14
|
+
};
|
|
15
|
+
const parseBookmarkRangeMarker = (node) => {
|
|
16
|
+
const marker = {
|
|
17
|
+
...parseMarkupRangeMarker(node),
|
|
18
|
+
name: getAttribute(node, "w", "name") ?? ""
|
|
19
|
+
};
|
|
20
|
+
const colFirst = parseNumericAttribute(node, "w", "colFirst");
|
|
21
|
+
if (colFirst !== void 0) marker.colFirst = colFirst;
|
|
22
|
+
const colLast = parseNumericAttribute(node, "w", "colLast");
|
|
23
|
+
if (colLast !== void 0) marker.colLast = colLast;
|
|
24
|
+
return marker;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* `w:author` is required on `CT_MoveBookmark`, so an absent one takes the same
|
|
28
|
+
* `Unknown` fallback a tracked change takes rather than leaving the saved
|
|
29
|
+
* package short of an attribute the schema demands. `w:date` is required too,
|
|
30
|
+
* but inventing a timestamp would state a fact about the document that is not
|
|
31
|
+
* true, so an absent date stays absent.
|
|
32
|
+
*/
|
|
33
|
+
const parseMoveBookmarkMarker = (node) => {
|
|
34
|
+
const author = (getAttribute(node, "w", "author") ?? "").trim();
|
|
35
|
+
const marker = {
|
|
36
|
+
...parseBookmarkRangeMarker(node),
|
|
37
|
+
author: author.length > 0 ? author : "Unknown"
|
|
38
|
+
};
|
|
39
|
+
const date = (getAttribute(node, "w", "date") ?? "").trim();
|
|
40
|
+
if (date.length > 0) marker.date = date;
|
|
41
|
+
return marker;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { parseBookmarkRangeMarker, parseMarkupRangeMarker, parseMoveBookmarkMarker };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/docx/noteReferenceStyles.d.ts
|
|
3
|
+
/** The id `commentSerializer` and `paragraphSerializer` write. */
|
|
4
|
+
declare const COMMENT_REFERENCE_STYLE_ID = "CommentReference";
|
|
5
|
+
/** The ids `noteSerializer` writes for the two note kinds. */
|
|
6
|
+
declare const FOOTNOTE_REFERENCE_STYLE_ID = "FootnoteReference";
|
|
7
|
+
declare const ENDNOTE_REFERENCE_STYLE_ID = "EndnoteReference";
|
|
8
|
+
/** Which reference marks a package actually contains. */
|
|
9
|
+
type NoteReferenceNeeds = {
|
|
10
|
+
comments: boolean;
|
|
11
|
+
footnotes: boolean;
|
|
12
|
+
endnotes: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** What a package's content requires, read off the model rather than guessed. */
|
|
15
|
+
declare const noteReferenceNeeds: (pkg: {
|
|
16
|
+
comments?: unknown[] | undefined;
|
|
17
|
+
footnotes?: unknown[] | undefined;
|
|
18
|
+
endnotes?: unknown[] | undefined;
|
|
19
|
+
}) => NoteReferenceNeeds;
|
|
20
|
+
/**
|
|
21
|
+
* The reference styles a package needs and does not already define, by id.
|
|
22
|
+
*
|
|
23
|
+
* Returns the definitions to append rather than a mutated style table: the
|
|
24
|
+
* caller owns the document, and a document that already defines the style
|
|
25
|
+
* (under any id folio recognises) keeps its own.
|
|
26
|
+
*/
|
|
27
|
+
declare const missingNoteReferenceStyles: (styles: document_d_exports.StyleDefinitions | undefined, needs: NoteReferenceNeeds) => document_d_exports.Style[];
|
|
28
|
+
//#endregion
|
|
29
|
+
export { COMMENT_REFERENCE_STYLE_ID, ENDNOTE_REFERENCE_STYLE_ID, FOOTNOTE_REFERENCE_STYLE_ID, NoteReferenceNeeds, missingNoteReferenceStyles, noteReferenceNeeds };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BUILT_IN_STYLE_NAME } from "./builtInStyles.js";
|
|
2
|
+
//#region src/docx/noteReferenceStyles.ts
|
|
3
|
+
/**
|
|
4
|
+
* The character styles folio's serializers write into every document that
|
|
5
|
+
* carries a comment or a note, and the definitions that keep those references
|
|
6
|
+
* from dangling.
|
|
7
|
+
*
|
|
8
|
+
* `commentSerializer`, `paragraphSerializer` and `noteSerializer` each emit
|
|
9
|
+
* `<w:rStyle w:val="…"/>` for the reference mark, because that is what Word
|
|
10
|
+
* writes and what makes the mark superscript. Nothing guaranteed the document
|
|
11
|
+
* *defined* those styles: a package folio assembled from the generic style set
|
|
12
|
+
* referenced `FootnoteReference` while declaring only seven paragraph styles,
|
|
13
|
+
* so the mark rendered as body text. One owner here, so a serializer and the
|
|
14
|
+
* style table cannot disagree about the id.
|
|
15
|
+
*/
|
|
16
|
+
/** The id `commentSerializer` and `paragraphSerializer` write. */
|
|
17
|
+
const COMMENT_REFERENCE_STYLE_ID = "CommentReference";
|
|
18
|
+
/** The ids `noteSerializer` writes for the two note kinds. */
|
|
19
|
+
const FOOTNOTE_REFERENCE_STYLE_ID = "FootnoteReference";
|
|
20
|
+
const ENDNOTE_REFERENCE_STYLE_ID = "EndnoteReference";
|
|
21
|
+
/** The default character style Word bases these on, when the package has one. */
|
|
22
|
+
const DEFAULT_CHARACTER_STYLE_ID = "DefaultParagraphFont";
|
|
23
|
+
const referenceStyle = (styleId, name, superscript) => ({
|
|
24
|
+
styleId,
|
|
25
|
+
type: "character",
|
|
26
|
+
name,
|
|
27
|
+
uiPriority: 99,
|
|
28
|
+
semiHidden: true,
|
|
29
|
+
unhideWhenUsed: true,
|
|
30
|
+
rPr: superscript ? { vertAlign: "superscript" } : { fontSize: 16 }
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* The definition for each reference style, keyed by the need that requires it.
|
|
34
|
+
* Word's comment reference is 8pt body text; the note references are
|
|
35
|
+
* superscript.
|
|
36
|
+
*/
|
|
37
|
+
const REFERENCE_STYLES = {
|
|
38
|
+
comments: () => referenceStyle(COMMENT_REFERENCE_STYLE_ID, BUILT_IN_STYLE_NAME.commentReference, false),
|
|
39
|
+
footnotes: () => referenceStyle(FOOTNOTE_REFERENCE_STYLE_ID, BUILT_IN_STYLE_NAME.footnoteReference, true),
|
|
40
|
+
endnotes: () => referenceStyle(ENDNOTE_REFERENCE_STYLE_ID, BUILT_IN_STYLE_NAME.endnoteReference, true)
|
|
41
|
+
};
|
|
42
|
+
/** What a package's content requires, read off the model rather than guessed. */
|
|
43
|
+
const noteReferenceNeeds = (pkg) => ({
|
|
44
|
+
comments: (pkg.comments?.length ?? 0) > 0,
|
|
45
|
+
footnotes: (pkg.footnotes?.length ?? 0) > 0,
|
|
46
|
+
endnotes: (pkg.endnotes?.length ?? 0) > 0
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* The reference styles a package needs and does not already define, by id.
|
|
50
|
+
*
|
|
51
|
+
* Returns the definitions to append rather than a mutated style table: the
|
|
52
|
+
* caller owns the document, and a document that already defines the style
|
|
53
|
+
* (under any id folio recognises) keeps its own.
|
|
54
|
+
*/
|
|
55
|
+
const missingNoteReferenceStyles = (styles, needs) => {
|
|
56
|
+
const defined = new Set((styles?.styles ?? []).map((style) => style.styleId));
|
|
57
|
+
const basedOn = defined.has(DEFAULT_CHARACTER_STYLE_ID) ? DEFAULT_CHARACTER_STYLE_ID : void 0;
|
|
58
|
+
const missing = [];
|
|
59
|
+
for (const [need, create] of Object.entries(REFERENCE_STYLES)) {
|
|
60
|
+
if (!needs[need]) continue;
|
|
61
|
+
const style = create();
|
|
62
|
+
if (!defined.has(style.styleId)) missing.push(basedOn === void 0 ? style : {
|
|
63
|
+
...style,
|
|
64
|
+
basedOn
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return missing;
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { COMMENT_REFERENCE_STYLE_ID, ENDNOTE_REFERENCE_STYLE_ID, FOOTNOTE_REFERENCE_STYLE_ID, missingNoteReferenceStyles, noteReferenceNeeds };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isNumberingReference } from "./numberingReference.js";
|
|
1
2
|
import { formatOoxmlCounter, padDecimal } from "./ooxmlCounterFormatter.js";
|
|
2
3
|
import { LevelSuffixSchema, narrowEnum } from "./parserEnums.js";
|
|
3
4
|
import { parseRunProperties } from "./runParser.js";
|
|
@@ -529,7 +530,7 @@ function createNumberingMap(definitions) {
|
|
|
529
530
|
*/
|
|
530
531
|
function computeListRendering(numPr, numbering) {
|
|
531
532
|
const { numId, ilvl = 0 } = numPr;
|
|
532
|
-
if (numId
|
|
533
|
+
if (!isNumberingReference(numId)) return null;
|
|
533
534
|
const level = numbering.getLevel(numId, ilvl);
|
|
534
535
|
if (!level) return null;
|
|
535
536
|
const levelNumFmts = [];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/docx/numberingReference.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The reserved `w:numId` value that means "no numbering".
|
|
4
|
+
*
|
|
5
|
+
* ECMA-376 (17.9.18 `numId`, 17.9.19 `numPr`) reserves 0: it names no `w:num`,
|
|
6
|
+
* it switches numbering off, and on a style it cancels the numbering the style
|
|
7
|
+
* would otherwise inherit through `w:basedOn` (Word writes it on, for example,
|
|
8
|
+
* a heading-based style that must not be numbered). It must therefore survive a
|
|
9
|
+
* round trip: dropping the `w:numPr` would hand the numbering back.
|
|
10
|
+
*/
|
|
11
|
+
declare const NO_NUMBERING_NUM_ID = 0;
|
|
12
|
+
/**
|
|
13
|
+
* Whether a `w:numId` names a numbering definition to resolve.
|
|
14
|
+
*
|
|
15
|
+
* Every lookup or validation against `numbering.nums` goes through this: an
|
|
16
|
+
* absent id has nothing to resolve, and {@link NO_NUMBERING_NUM_ID} is the
|
|
17
|
+
* "none" sentinel, never a dangling reference.
|
|
18
|
+
*/
|
|
19
|
+
declare const isNumberingReference: (numId: number | undefined) => numId is number;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { NO_NUMBERING_NUM_ID, isNumberingReference };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/docx/numberingReference.ts
|
|
2
|
+
/**
|
|
3
|
+
* The reserved `w:numId` value that means "no numbering".
|
|
4
|
+
*
|
|
5
|
+
* ECMA-376 (17.9.18 `numId`, 17.9.19 `numPr`) reserves 0: it names no `w:num`,
|
|
6
|
+
* it switches numbering off, and on a style it cancels the numbering the style
|
|
7
|
+
* would otherwise inherit through `w:basedOn` (Word writes it on, for example,
|
|
8
|
+
* a heading-based style that must not be numbered). It must therefore survive a
|
|
9
|
+
* round trip: dropping the `w:numPr` would hand the numbering back.
|
|
10
|
+
*/
|
|
11
|
+
const NO_NUMBERING_NUM_ID = 0;
|
|
12
|
+
/**
|
|
13
|
+
* Whether a `w:numId` names a numbering definition to resolve.
|
|
14
|
+
*
|
|
15
|
+
* Every lookup or validation against `numbering.nums` goes through this: an
|
|
16
|
+
* absent id has nothing to resolve, and {@link NO_NUMBERING_NUM_ID} is the
|
|
17
|
+
* "none" sentinel, never a dangling reference.
|
|
18
|
+
*/
|
|
19
|
+
const isNumberingReference = (numId) => numId !== void 0 && numId !== 0;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { NO_NUMBERING_NUM_ID, isNumberingReference };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { NumberingMap } from "./numberingParser.js";
|
|
3
3
|
//#region src/docx/numberingReferenceNormalization.d.ts
|
|
4
|
+
/** The codes this normalisation is reported under, owned here, not at the caller. */
|
|
5
|
+
declare const UNNUMBERED_PARAGRAPH_WARNING: "unnumbered-paragraph";
|
|
6
|
+
declare const UNNUMBERED_STYLE_WARNING: "unnumbered-style";
|
|
4
7
|
type NormalizeNumberingReferencesInput = {
|
|
5
8
|
documentBody: document_d_exports.DocumentBody;
|
|
6
9
|
numbering: NumberingMap;
|
|
@@ -10,8 +13,17 @@ type NormalizeNumberingReferencesInput = {
|
|
|
10
13
|
endnotes?: readonly document_d_exports.Endnote[];
|
|
11
14
|
};
|
|
12
15
|
type NormalizeNumberingReferencesResult = {
|
|
13
|
-
|
|
16
|
+
unnumberedDanglingReferences: number;
|
|
14
17
|
};
|
|
15
18
|
declare const normalizeNumberingReferences: ({ documentBody, numbering, headers, footers, footnotes, endnotes }: NormalizeNumberingReferencesInput) => NormalizeNumberingReferencesResult;
|
|
19
|
+
type NormalizeStyleNumberingReferencesInput = {
|
|
20
|
+
styles: readonly document_d_exports.Style[];
|
|
21
|
+
numbering: NumberingMap | undefined;
|
|
22
|
+
};
|
|
23
|
+
type NormalizeStyleNumberingReferencesResult = {
|
|
24
|
+
/** Style ids whose dangling reference became the "no numbering" sentinel. */
|
|
25
|
+
unnumberedStyleIds: string[];
|
|
26
|
+
};
|
|
27
|
+
declare const normalizeStyleNumberingReferences: ({ styles, numbering }: NormalizeStyleNumberingReferencesInput) => NormalizeStyleNumberingReferencesResult;
|
|
16
28
|
//#endregion
|
|
17
|
-
export { normalizeNumberingReferences };
|
|
29
|
+
export { UNNUMBERED_PARAGRAPH_WARNING, UNNUMBERED_STYLE_WARNING, normalizeNumberingReferences, normalizeStyleNumberingReferences };
|
|
@@ -1,7 +1,37 @@
|
|
|
1
|
+
import { isNumberingReference } from "./numberingReference.js";
|
|
1
2
|
import { visitDocxParagraphs } from "./paragraphTraversal.js";
|
|
3
|
+
import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
|
|
2
4
|
//#region src/docx/numberingReferenceNormalization.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse-boundary tolerance for `w:numPr` numbering references.
|
|
7
|
+
*
|
|
8
|
+
* A file Word opens must never reach a panic, so a reference that resolves to
|
|
9
|
+
* nothing is repaired here, on both tiers that can carry one: the paragraph and
|
|
10
|
+
* the paragraph style. Downstream code (and `assertStyleNumberingReferences` in
|
|
11
|
+
* particular) can then treat a numbering reference as resolvable.
|
|
12
|
+
*
|
|
13
|
+
* The repair writes the sentinel rather than deleting the `w:numPr`. ECMA-376
|
|
14
|
+
* 17.9.18 reserves `w:numId w:val="0"` for "the removal of numbering properties
|
|
15
|
+
* at a particular level in the style hierarchy"; deleting the element instead
|
|
16
|
+
* removes nothing, it only uncovers the tier below, handing the paragraph its
|
|
17
|
+
* `w:pStyle` numbering or the style its `w:basedOn` numbering. A source that
|
|
18
|
+
* shows no number would come back numbered.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Whether a `w:numId` still reaches a level definition: a `w:num` that names a
|
|
22
|
+
* `w:abstractNum` the numbering part defines. Both hops can dangle, and a
|
|
23
|
+
* `w:num` with no `w:abstractNum` numbers nothing just as a missing one does.
|
|
24
|
+
*/
|
|
25
|
+
const resolvesNumbering = (numId, numbering) => {
|
|
26
|
+
if (!numbering) return false;
|
|
27
|
+
const abstractNumId = numbering.getAbstractNumId(numId);
|
|
28
|
+
return abstractNumId !== null && numbering.getAbstract(abstractNumId) !== null;
|
|
29
|
+
};
|
|
30
|
+
/** The codes this normalisation is reported under, owned here, not at the caller. */
|
|
31
|
+
const UNNUMBERED_PARAGRAPH_WARNING = PARSE_WARNING_CODES.unnumberedParagraph;
|
|
32
|
+
const UNNUMBERED_STYLE_WARNING = PARSE_WARNING_CODES.unnumberedStyle;
|
|
3
33
|
const normalizeNumberingReferences = ({ documentBody, numbering, headers, footers, footnotes, endnotes }) => {
|
|
4
|
-
let
|
|
34
|
+
let unnumberedDanglingReferences = 0;
|
|
5
35
|
visitDocxParagraphs({
|
|
6
36
|
documentBody,
|
|
7
37
|
headers,
|
|
@@ -9,14 +39,26 @@ const normalizeNumberingReferences = ({ documentBody, numbering, headers, footer
|
|
|
9
39
|
footnotes,
|
|
10
40
|
endnotes
|
|
11
41
|
}, (paragraph) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
42
|
+
const formatting = paragraph.formatting;
|
|
43
|
+
const numId = formatting?.numPr?.numId;
|
|
44
|
+
if (!formatting || !isNumberingReference(numId) || resolvesNumbering(numId, numbering)) return;
|
|
45
|
+
formatting.numPr = { numId: 0 };
|
|
46
|
+
delete formatting.numPrFromStyle;
|
|
47
|
+
delete paragraph.listRendering;
|
|
48
|
+
unnumberedDanglingReferences += 1;
|
|
18
49
|
});
|
|
19
|
-
return {
|
|
50
|
+
return { unnumberedDanglingReferences };
|
|
51
|
+
};
|
|
52
|
+
const normalizeStyleNumberingReferences = ({ styles, numbering }) => {
|
|
53
|
+
const unnumberedStyleIds = [];
|
|
54
|
+
for (const style of styles) {
|
|
55
|
+
const pPr = style.pPr;
|
|
56
|
+
const numId = pPr?.numPr?.numId;
|
|
57
|
+
if (!pPr || !isNumberingReference(numId) || resolvesNumbering(numId, numbering)) continue;
|
|
58
|
+
pPr.numPr = { numId: 0 };
|
|
59
|
+
unnumberedStyleIds.push(style.styleId);
|
|
60
|
+
}
|
|
61
|
+
return { unnumberedStyleIds };
|
|
20
62
|
};
|
|
21
63
|
//#endregion
|
|
22
|
-
export { normalizeNumberingReferences };
|
|
64
|
+
export { UNNUMBERED_PARAGRAPH_WARNING, UNNUMBERED_STYLE_WARNING, normalizeNumberingReferences, normalizeStyleNumberingReferences };
|
|
@@ -1,23 +1,4 @@
|
|
|
1
1
|
//#region src/docx/paraIdRangeNormalization.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Keep every paragraph id a package carries inside the range the schema gives
|
|
4
|
-
* it.
|
|
5
|
-
*
|
|
6
|
-
* `w14:paraId`, `w14:textId` and the comment-part ids that reference a
|
|
7
|
-
* paragraph are `ST_LongHexNumber` with a maximum: the value has to be below
|
|
8
|
-
* `0x80000000`, so the ids are 31-bit. Producers exist that write eight hex
|
|
9
|
-
* digits without that bound, and folio preserves the ids a document arrives
|
|
10
|
-
* with — so a package can carry an out-of-range id in, and a save that copies
|
|
11
|
-
* it through hands a consumer a package it will refuse.
|
|
12
|
-
*
|
|
13
|
-
* {@link paraIdInRange} is the one mapping, and it is a pure function of the
|
|
14
|
-
* value alone. That is what lets the parser and the save agree without
|
|
15
|
-
* consulting each other: a paragraph's id in the model is the id the file gets,
|
|
16
|
-
* so bringing an id into range does not make a document's own identity move
|
|
17
|
-
* under it between reading and writing. The package pass below is the same
|
|
18
|
-
* mapping applied to every attribute that carries such an id, so a paragraph
|
|
19
|
-
* and every reference to it move together.
|
|
20
|
-
*/
|
|
21
2
|
/**
|
|
22
3
|
* `value` when it already fits, and a value derived from it when it does not.
|
|
23
4
|
*
|