@stll/folio-core 0.60.0 → 0.62.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/README.md +13 -0
- package/dist/ai-edits/apply.js +139 -32
- package/dist/ai-edits/headless.d.ts +3 -0
- package/dist/ai-edits/headless.js +70 -75
- package/dist/ai-edits/note-story-inventory.d.ts +7 -0
- package/dist/ai-edits/note-story-inventory.js +11 -0
- package/dist/ai-edits/read.js +16 -9
- package/dist/ai-edits/revisionStretches.js +52 -1
- package/dist/ai-edits/table-row-column-mutations.js +6 -1
- package/dist/compare/reproducible-package.js +2 -1
- package/dist/compare/verification.js +1 -0
- package/dist/compat/eigenpal.d.ts +3 -1
- package/dist/controller/canonicalClipboard.js +2 -1
- package/dist/controller/canonicalListRendering.d.ts +4 -6
- package/dist/controller/canonicalListRendering.js +3 -157
- package/dist/controller/headerFooterEditorManager.d.ts +1 -0
- package/dist/controller/headerFooterEditorManager.js +11 -0
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +3 -1
- package/dist/controller/layoutPipeline.d.ts +3 -1
- package/dist/controller/layoutPipeline.js +13 -4
- package/dist/controller/layoutSession.d.ts +2 -1
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +28 -12
- package/dist/display-list/build/paragraphPrimitives.js +15 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -5
- package/dist/display-list/types.d.ts +7 -3
- package/dist/docx/canonicalStoryRepack.js +3 -2
- package/dist/docx/commentTextParagraph.d.ts +6 -0
- package/dist/docx/commentTextParagraph.js +15 -0
- package/dist/docx/conformance.js +6 -1
- package/dist/docx/diagramPreview.js +2 -1
- package/dist/docx/documentParser.d.ts +13 -1
- package/dist/docx/documentParser.js +1 -1
- package/dist/docx/encryption/compoundFile.d.ts +0 -8
- package/dist/docx/encryption/compoundFile.js +2 -1
- package/dist/docx/encryption/cryptoBytes.d.ts +2 -2
- package/dist/docx/encryption/cryptoBytes.js +3 -18
- package/dist/docx/encryption/encryptionInfo.d.ts +0 -5
- package/dist/docx/encryption/encryptionInfo.js +2 -1
- package/dist/docx/ensureParaIds.js +2 -1
- package/dist/docx/groupDrawingParser.js +28 -13
- package/dist/docx/listModelNormalization.d.ts +10 -0
- package/dist/docx/listModelNormalization.js +166 -0
- package/dist/docx/metadataPrivacy.js +3 -2
- package/dist/docx/metafileRaster.js +2 -1
- package/dist/docx/packageParts.js +6 -5
- package/dist/docx/paragraphParser.js +6 -4
- package/dist/docx/parser.js +5 -4
- package/dist/docx/preservedRunContent.js +11 -2
- package/dist/docx/removeHeaderFooterParts.js +8 -7
- package/dist/docx/replyToComment.js +3 -13
- package/dist/docx/rezip.js +88 -89
- package/dist/docx/runParser.js +12 -6
- package/dist/docx/runPropertyPresence.d.ts +11 -0
- package/dist/docx/runPropertyPresence.js +14 -0
- package/dist/docx/selectiveSave.js +15 -14
- package/dist/docx/serializer/runSerializer.js +3 -2
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
- package/dist/docx/server/boundedArchive.js +2 -1
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -1
- package/dist/docx/server/inspectDocxPackage.js +5 -1
- package/dist/docx/server/validateDocxConformance.js +2 -1
- package/dist/docx/tableParser.js +7 -4
- package/dist/docx/tableRowPropertyPresence.d.ts +9 -0
- package/dist/docx/tableRowPropertyPresence.js +15 -0
- package/dist/docx/unzip.js +2 -1
- package/dist/docx/xmlEncoding.js +6 -5
- package/dist/fonts/fontsourceFaces.js +2 -1
- package/dist/fonts/sfnt/parse.js +6 -9
- package/dist/fonts/sfnt/subset.js +2 -1
- package/dist/fonts/sfnt/tables.js +2 -3
- package/dist/fonts/sfnt/woff.js +2 -1
- package/dist/i18n/messages/ar.gen.js +1 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/cs.gen.js +1 -0
- package/dist/i18n/messages/de.gen.js +1 -0
- package/dist/i18n/messages/en.gen.js +1 -0
- package/dist/i18n/messages/es.gen.js +1 -0
- package/dist/i18n/messages/et.gen.js +1 -0
- package/dist/i18n/messages/fr.gen.js +1 -0
- package/dist/i18n/messages/he.gen.js +1 -0
- package/dist/i18n/messages/hi.gen.js +1 -0
- package/dist/i18n/messages/hu.gen.js +1 -0
- package/dist/i18n/messages/lt.gen.js +1 -0
- package/dist/i18n/messages/lv.gen.js +1 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/i18n/messages/pl.gen.js +1 -0
- package/dist/i18n/messages/pt-BR.gen.js +1 -0
- package/dist/i18n/messages/sk.gen.js +1 -0
- package/dist/i18n/messages/tr.gen.js +1 -0
- package/dist/i18n/messages/zh-CN.gen.js +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/internal/revisionResolutionInline.d.ts +2 -1
- package/dist/internal/revisionResolutionInline.js +22 -1
- package/dist/internal/wholeStoryRevisionResolution.js +24 -7
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +1 -1
- package/dist/layout-bridge/convert/endnoteLayout.js +1 -3
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +2 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +4 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +13 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +12 -15
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/crossRunWords.js +12 -2
- package/dist/layout-engine/noteAreaFlow.d.ts +4 -4
- package/dist/layout-engine/noteAreaFlow.js +12 -6
- package/dist/layout-engine/types.d.ts +5 -2
- package/dist/layout-painter/index.d.ts +1 -1
- package/dist/managers/AutoSaveManager.js +2 -1
- package/dist/managers/EditorModeManager.d.ts +10 -1
- package/dist/managers/EditorModeManager.js +15 -1
- package/dist/managers/FindReplaceManager.d.ts +13 -6
- package/dist/managers/FindReplaceManager.js +15 -9
- package/dist/managers/TableSelectionManager.d.ts +1 -1
- package/dist/managers/autoSaveCodec.js +2 -6
- package/dist/managers/reviewDisplayMode.d.ts +8 -0
- package/dist/managers/reviewDisplayMode.js +15 -0
- package/dist/paged-layout/editorScrollRoot.d.ts +3 -1
- package/dist/paged-layout/editorScrollRoot.js +2 -2
- package/dist/paged-layout/pageText.d.ts +11 -2
- package/dist/paged-layout/pageText.js +8 -3
- package/dist/pdf/fonts.js +5 -14
- package/dist/pdf/images.js +4 -2
- package/dist/pdf/objects.d.ts +0 -11
- package/dist/pdf/objects.js +7 -9
- package/dist/pdf/writePdf.js +2 -1
- package/dist/prosemirror/commands/comments.js +51 -13
- package/dist/prosemirror/commentRangeInlineAtoms.d.ts +40 -0
- package/dist/prosemirror/commentRangeInlineAtoms.js +33 -0
- package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
- package/dist/prosemirror/containerFinalParagraph.js +8 -8
- package/dist/prosemirror/conversion/fromProseDoc.js +14 -8
- package/dist/prosemirror/conversion/toProseDoc.js +16 -23
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
- package/dist/prosemirror/fieldRepresentation.js +4 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +48 -2
- package/dist/prosemirror/findReplaceSelection.js +153 -38
- package/dist/prosemirror/inlineDisplayText.d.ts +10 -0
- package/dist/prosemirror/inlineDisplayText.js +29 -0
- package/dist/prosemirror/markupViewProjection.d.ts +10 -1
- package/dist/prosemirror/markupViewProjection.js +21 -3
- package/dist/prosemirror/plugins/transactionInvariants.js +6 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +15 -1
- package/dist/prosemirror/replacedAnnotations.js +71 -12
- package/dist/prosemirror/runFormattingReconciliation.d.ts +3 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -2
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +5 -7
- package/dist/prosemirror/runIdentityAcrossRevisions.js +66 -38
- package/dist/prosemirror/runPropertyChangeResolution.js +13 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/utils/base64.d.ts +1 -31
- package/dist/utils/base64.js +19 -33
- package/dist/utils/clipboard.js +5 -4
- package/dist/utils/colorResolver.js +11 -2
- package/dist/utils/findMatchView.d.ts +32 -0
- package/dist/utils/findMatchView.js +406 -0
- package/dist/utils/findReplace.d.ts +67 -4
- package/dist/utils/findReplace.js +359 -37
- package/dist/utils/findSearchKey.d.ts +29 -0
- package/dist/utils/findSearchKey.js +34 -0
- package/dist/utils/replaceText.js +138 -94
- package/dist/utils/sliceText.d.ts +2 -0
- package/dist/utils/sliceText.js +2 -0
- package/dist/utils/textEncoding.d.ts +2 -0
- package/dist/utils/textEncoding.js +2 -0
- package/dist/utils/tiffConverter.d.ts +0 -9
- package/dist/utils/tiffConverter.js +2 -4
- package/package.json +51 -25
package/dist/docx/runParser.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseHorizontalScalePercent } from "../utils/horizontalScale.js";
|
|
2
|
+
import { sliceText } from "../utils/sliceText.js";
|
|
2
3
|
import { NO_MODELLED_ATTRIBUTES, attributeRemainder } from "./attributeRemainder.js";
|
|
3
4
|
import { CAPTURE, dispatchChildrenWithContext, keptUnless, ownedElsewhere, sequencePositions } from "./containerChildren.js";
|
|
4
5
|
import { parseDiagramPreview } from "./diagramPreview.js";
|
|
@@ -10,6 +11,7 @@ import { EmphasisMarkSchema, FontHintSchema, FontThemeSchema, HighlightColorSche
|
|
|
10
11
|
import { preserveRunChild } from "./preservedRunContent.js";
|
|
11
12
|
import { standalonePreviewLedger } from "./previewBudget.js";
|
|
12
13
|
import { parseBoundaryJoins } from "./reviewResolutionProvenance.js";
|
|
14
|
+
import { isEmptyRunPropertiesAttribute, omitsPreviousRunProperties, retainsEmptyRunProperties } from "./runPropertyPresence.js";
|
|
13
15
|
import { parseShading } from "./shadingParser.js";
|
|
14
16
|
import { captureShapeAlternateContent } from "./shapeAlternateContent.js";
|
|
15
17
|
import { parseShapeFromDrawing, shouldPreserveRawShapeDrawing } from "./shapeParser.js";
|
|
@@ -48,7 +50,11 @@ import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
|
48
50
|
* attacker-sized string per run.
|
|
49
51
|
*/
|
|
50
52
|
const MAX_LANGUAGE_TAG_LENGTH = 35;
|
|
51
|
-
const truncateLanguageTag = (value) => value === void 0 ? void 0 :
|
|
53
|
+
const truncateLanguageTag = (value) => value === void 0 ? void 0 : sliceText({
|
|
54
|
+
text: value,
|
|
55
|
+
units: "codeUnits",
|
|
56
|
+
end: MAX_LANGUAGE_TAG_LENGTH
|
|
57
|
+
});
|
|
52
58
|
function parseColorValue({ rgb, themeColor, themeTint, themeShade, element }) {
|
|
53
59
|
const color = {};
|
|
54
60
|
if (rgb && rgb !== "auto") color.rgb = rgb;
|
|
@@ -429,7 +435,7 @@ function parseRunProperties(rPr, theme, owner) {
|
|
|
429
435
|
});
|
|
430
436
|
if (preserved) formatting.preserved = preserved;
|
|
431
437
|
const children = getChildElements(rPr);
|
|
432
|
-
if (owner
|
|
438
|
+
if (owner !== RUN_PROPERTY_OWNERS.standalone && Object.keys(formatting).length === 0 && children.length > 0 && children.every((child) => WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(child) ?? "") && Object.hasOwn(OWNED_BY_A_SIBLING_RECORD[owner], getLocalName(child.name)))) return;
|
|
433
439
|
return formatting;
|
|
434
440
|
}
|
|
435
441
|
function parseRunPropertyChanges(rPr, theme, currentFormatting) {
|
|
@@ -443,7 +449,7 @@ function parseRunPropertyChanges(rPr, theme, currentFormatting) {
|
|
|
443
449
|
const boundaryJoins = parseBoundaryJoins(changeElement);
|
|
444
450
|
if (boundaryJoins !== void 0) change.boundaryJoins = boundaryJoins;
|
|
445
451
|
const previousFormatting = parseRunProperties(previousRPr, theme, RUN_PROPERTY_OWNERS.standalone);
|
|
446
|
-
if (previousFormatting) change.previousFormatting = previousFormatting;
|
|
452
|
+
if (previousFormatting && (!omitsPreviousRunProperties(changeElement) || Object.keys(previousFormatting).length > 0)) change.previousFormatting = previousFormatting;
|
|
447
453
|
if (currentFormatting) change.currentFormatting = currentFormatting;
|
|
448
454
|
return change;
|
|
449
455
|
});
|
|
@@ -789,7 +795,7 @@ function parseRun(node, _styles, theme, rels = null, media = null, rootXmlns = {
|
|
|
789
795
|
};
|
|
790
796
|
const rPr = findChild(node, "w", "rPr");
|
|
791
797
|
if (rPr) {
|
|
792
|
-
const formattingResult = parseRunProperties(rPr, theme, RUN_PROPERTY_OWNERS.run);
|
|
798
|
+
const formattingResult = parseRunProperties(rPr, theme, RUN_PROPERTY_OWNERS.run) ?? (retainsEmptyRunProperties(node) ? {} : void 0);
|
|
793
799
|
if (formattingResult) run.formatting = formattingResult;
|
|
794
800
|
const propertyChangesResult = parseRunPropertyChanges(rPr, theme, run.formatting);
|
|
795
801
|
if (propertyChangesResult) run.propertyChanges = propertyChangesResult;
|
|
@@ -798,8 +804,8 @@ function parseRun(node, _styles, theme, rels = null, media = null, rootXmlns = {
|
|
|
798
804
|
const remainder = attributeRemainder({
|
|
799
805
|
element: node,
|
|
800
806
|
modelled: NO_MODELLED_ATTRIBUTES
|
|
801
|
-
});
|
|
802
|
-
if (remainder) run.preservedAttributes = remainder;
|
|
807
|
+
})?.filter((attribute) => !isEmptyRunPropertiesAttribute(attribute));
|
|
808
|
+
if (remainder?.length) run.preservedAttributes = remainder;
|
|
803
809
|
return run;
|
|
804
810
|
}
|
|
805
811
|
/**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { XmlElement } from "./xmlParser.js";
|
|
3
|
+
//#region src/docx/runPropertyPresence.d.ts
|
|
4
|
+
declare const EMPTY_RUN_PROPERTIES_ATTRIBUTE = "emptyRunProperties";
|
|
5
|
+
declare const retainsEmptyRunProperties: (element: XmlElement) => boolean;
|
|
6
|
+
declare const omitsPreviousRunProperties: (element: XmlElement) => boolean;
|
|
7
|
+
declare const serializePreviousRunProperties: (properties: document_d_exports.TextFormatting | undefined) => string;
|
|
8
|
+
declare const serializeEmptyRunProperties: (run: document_d_exports.Run) => string[];
|
|
9
|
+
declare const isEmptyRunPropertiesAttribute: ({ namespace, name }: Pick<document_d_exports.PreservedAttribute, "namespace" | "name">) => boolean;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { EMPTY_RUN_PROPERTIES_ATTRIBUTE, isEmptyRunPropertiesAttribute, omitsPreviousRunProperties, retainsEmptyRunProperties, serializeEmptyRunProperties, serializePreviousRunProperties };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OOXML_NAMESPACES } from "./serializer/partNamespaces.js";
|
|
2
|
+
import { getAttributeByNamespaceUri } from "./xmlParser.js";
|
|
3
|
+
import { EMPTY_PROPERTY_SETS } from "@stll/docx-core/ops";
|
|
4
|
+
//#region src/docx/runPropertyPresence.ts
|
|
5
|
+
const EMPTY_RUN_PROPERTIES_ATTRIBUTE = "emptyRunProperties";
|
|
6
|
+
const PREVIOUS_PROPERTIES_ATTRIBUTE = "previousProperties";
|
|
7
|
+
const HISTORY_NAMESPACES = /* @__PURE__ */ new Set([OOXML_NAMESPACES.folio.uri]);
|
|
8
|
+
const retainsEmptyRunProperties = (element) => getAttributeByNamespaceUri(element, HISTORY_NAMESPACES, EMPTY_RUN_PROPERTIES_ATTRIBUTE) === EMPTY_PROPERTY_SETS.KEEP;
|
|
9
|
+
const omitsPreviousRunProperties = (element) => getAttributeByNamespaceUri(element, HISTORY_NAMESPACES, PREVIOUS_PROPERTIES_ATTRIBUTE) === EMPTY_PROPERTY_SETS.OMIT;
|
|
10
|
+
const serializePreviousRunProperties = (properties) => properties === void 0 ? ` folio:${PREVIOUS_PROPERTIES_ATTRIBUTE}="${EMPTY_PROPERTY_SETS.OMIT}"` : "";
|
|
11
|
+
const serializeEmptyRunProperties = (run) => run.propertyChanges?.length && run.formatting !== void 0 && Object.keys(run.formatting).length === 0 ? [`folio:${EMPTY_RUN_PROPERTIES_ATTRIBUTE}="${EMPTY_PROPERTY_SETS.KEEP}"`] : [];
|
|
12
|
+
const isEmptyRunPropertiesAttribute = ({ namespace, name }) => namespace === OOXML_NAMESPACES.folio.uri && name === "emptyRunProperties";
|
|
13
|
+
//#endregion
|
|
14
|
+
export { EMPTY_RUN_PROPERTIES_ATTRIBUTE, isEmptyRunPropertiesAttribute, omitsPreviousRunProperties, retainsEmptyRunProperties, serializeEmptyRunProperties, serializePreviousRunProperties };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText, encodeUtf8 } from "../utils/textEncoding.js";
|
|
1
2
|
import { parseCommentsExtended } from "./commentParser.js";
|
|
2
3
|
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
3
4
|
import { hasUnsynthesizedReplyRanges } from "./commentReplyMarkers.js";
|
|
@@ -46,7 +47,7 @@ async function patchNoteParts(zip, doc, candidateIds, updates) {
|
|
|
46
47
|
const patchPart = async (conventionalLowerPath, serialize) => {
|
|
47
48
|
const file = findPart(conventionalLowerPath);
|
|
48
49
|
if (!file) return true;
|
|
49
|
-
const originalXml = await file.async("
|
|
50
|
+
const originalXml = await file.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
50
51
|
const originalIds = collectParaIds(originalXml);
|
|
51
52
|
const partIds = /* @__PURE__ */ new Set();
|
|
52
53
|
for (const id of remainingIds) if (originalIds.has(id)) partIds.add(id);
|
|
@@ -93,7 +94,7 @@ async function patchCommentsExtended(zip, plan, updates) {
|
|
|
93
94
|
const desiredXml = serializeCommentsExtended(plan);
|
|
94
95
|
const existing = findZipEntryCaseInsensitive(zip, COMMENTS_EXTENDED_PART_LOWER);
|
|
95
96
|
if (!desiredXml) return existing === null;
|
|
96
|
-
const baselineInfo = existing ? parseCommentsExtended(await existing.async("
|
|
97
|
+
const baselineInfo = existing ? parseCommentsExtended(await existing.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }))) : /* @__PURE__ */ new Map();
|
|
97
98
|
if (commentsExtendedInfoEqual(parseCommentsExtended(desiredXml), baselineInfo)) return true;
|
|
98
99
|
updates.set(existing?.name ?? "word/commentsExtended.xml", desiredXml);
|
|
99
100
|
return ensureCommentsExtendedPackaging(zip, updates);
|
|
@@ -106,12 +107,12 @@ async function patchCommentsExtended(zip, plan, updates) {
|
|
|
106
107
|
*/
|
|
107
108
|
async function ensureCommentsExtendedPackaging(zip, updates) {
|
|
108
109
|
const ctPath = "[Content_Types].xml";
|
|
109
|
-
const ctXml = updates.get(ctPath) ?? await zip.file(ctPath)?.async("
|
|
110
|
+
const ctXml = updates.get(ctPath) ?? await zip.file(ctPath)?.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
110
111
|
if (ctXml === void 0) return false;
|
|
111
112
|
const nextCt = addCommentsExtendedOverride(ctXml);
|
|
112
113
|
if (nextCt !== ctXml) updates.set(ctPath, nextCt);
|
|
113
114
|
const relsPath = "word/_rels/document.xml.rels";
|
|
114
|
-
const relsXml = updates.get(relsPath) ?? await zip.file(relsPath)?.async("
|
|
115
|
+
const relsXml = updates.get(relsPath) ?? await zip.file(relsPath)?.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
115
116
|
if (relsXml === void 0) return false;
|
|
116
117
|
const nextRels = addCommentsExtendedRelationship(relsXml);
|
|
117
118
|
if (nextRels !== relsXml) updates.set(relsPath, nextRels);
|
|
@@ -146,7 +147,7 @@ async function patchNumberingPart(zip, doc, updates) {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
if (!file) return false;
|
|
149
|
-
const originalXml = await file.async("
|
|
150
|
+
const originalXml = await file.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
150
151
|
const baselineXml = serializeNumberingXml(parseNumbering(originalXml).definitions);
|
|
151
152
|
const currentXml = serializeNumberingXml(numbering);
|
|
152
153
|
if (currentXml === baselineXml) return true;
|
|
@@ -177,7 +178,7 @@ const queueSettingsUpdates = async (zip, updates) => {
|
|
|
177
178
|
const settingsFile = zip.file("word/settings.xml");
|
|
178
179
|
if (!settingsFile) return;
|
|
179
180
|
const relsFile = zip.file("word/_rels/settings.xml.rels");
|
|
180
|
-
const filtered = withoutAttachedTemplate(await settingsFile.async("
|
|
181
|
+
const filtered = withoutAttachedTemplate(await settingsFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true })), await relsFile?.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true })));
|
|
181
182
|
if (filtered.settingsXml !== void 0) updates.set("word/settings.xml", filtered.settingsXml);
|
|
182
183
|
if (filtered.relsXml !== void 0) updates.set("word/_rels/settings.xml.rels", filtered.relsXml);
|
|
183
184
|
};
|
|
@@ -212,12 +213,12 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
212
213
|
for (const [path, file] of Object.entries(zip.files)) {
|
|
213
214
|
const lowerPath = path.toLowerCase();
|
|
214
215
|
if (file.dir || !lowerPath.startsWith("word/") || !lowerPath.endsWith(".xml")) continue;
|
|
215
|
-
sourceParts.set(path, await file.async("
|
|
216
|
+
sourceParts.set(path, await file.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true })));
|
|
216
217
|
}
|
|
217
218
|
for (const [path, xml] of normalizeImportedNumericIds(sourceParts)) if (xml !== sourceParts.get(path)) writeZipPart({
|
|
218
219
|
zip,
|
|
219
220
|
path,
|
|
220
|
-
data: xml
|
|
221
|
+
data: encodeUtf8(xml)
|
|
221
222
|
});
|
|
222
223
|
}
|
|
223
224
|
if (options.bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
@@ -229,7 +230,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
229
230
|
if (changedParaIds.size > 0 || structuralChange) {
|
|
230
231
|
const docXmlFile = zip.file("word/document.xml");
|
|
231
232
|
if (!docXmlFile) return null;
|
|
232
|
-
const originalDocXml = await docXmlFile.async("
|
|
233
|
+
const originalDocXml = await docXmlFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
233
234
|
const serializedDocXml = serializeDocument(doc, readRootNamespaceBindings(originalDocXml), {
|
|
234
235
|
xml: originalDocXml,
|
|
235
236
|
bodyAuthority: options.bodyAuthority,
|
|
@@ -239,7 +240,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
239
240
|
const originalBodyParaIds = structuralChange ? collectParaIds(originalDocXml) : void 0;
|
|
240
241
|
if (structuralChange && doc.package.numbering) {
|
|
241
242
|
const numberingFile = findZipEntryCaseInsensitive(zip, "word/numbering.xml");
|
|
242
|
-
const added = collectAddedNumberingDefs(numberingFile ? serializeNumberingXml(parseNumbering(await numberingFile.async("
|
|
243
|
+
const added = collectAddedNumberingDefs(numberingFile ? serializeNumberingXml(parseNumbering(await numberingFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }))).definitions) : "", serializeNumberingXml(doc.package.numbering));
|
|
243
244
|
if (added.abstractNums.size > 0 || added.nums.size > 0) return null;
|
|
244
245
|
}
|
|
245
246
|
const bodyChangedIds = /* @__PURE__ */ new Set();
|
|
@@ -262,7 +263,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
262
263
|
}
|
|
263
264
|
const sourceCommentsFile = findZipEntryCaseInsensitive(zip, "word/comments.xml");
|
|
264
265
|
const commentsPartPath = sourceCommentsFile?.name ?? "word/comments.xml";
|
|
265
|
-
const sourceCommentsXml = sourceCommentsFile ? await sourceCommentsFile.async("
|
|
266
|
+
const sourceCommentsXml = sourceCommentsFile ? await sourceCommentsFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true })) : void 0;
|
|
266
267
|
const commentsUnchanged = sourceCommentsXml !== void 0 && canReplayCommentsPart(doc, sourceCommentsXml);
|
|
267
268
|
if (!commentsUnchanged && (hasComments || ownsCommentsPart || sourceCommentsFile)) {
|
|
268
269
|
const commentsXml = serializeComments(commentPlan, sourceCommentsXml === void 0 ? void 0 : readRootNamespaceBindings(sourceCommentsXml));
|
|
@@ -271,13 +272,13 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
271
272
|
if (hasComments || ownsCommentsPart) {
|
|
272
273
|
const ctFile = zip.file("[Content_Types].xml");
|
|
273
274
|
if (ctFile) {
|
|
274
|
-
const ctXml = await ctFile.async("
|
|
275
|
+
const ctXml = await ctFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
275
276
|
if (!ctXml.toLowerCase().includes("/word/comments.xml")) updates.set("[Content_Types].xml", ctXml.replace("</Types>", `<Override PartName="/${commentsPartPath}" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`));
|
|
276
277
|
}
|
|
277
278
|
const relsPath = "word/_rels/document.xml.rels";
|
|
278
279
|
const relsFile = zip.file(relsPath);
|
|
279
280
|
if (relsFile) {
|
|
280
|
-
const relsXml = await relsFile.async("
|
|
281
|
+
const relsXml = await relsFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
281
282
|
if (!relsXml.toLowerCase().includes("comments.xml")) {
|
|
282
283
|
const maxId = findMaxRId(relsXml);
|
|
283
284
|
updates.set(relsPath, relsXml.replace("</Relationships>", `<Relationship Id="rId${maxId + 1}" Type="${RELATIONSHIP_TYPES.comments}" Target="${commentsPartPath.slice(5)}"/></Relationships>`));
|
|
@@ -307,7 +308,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
307
308
|
await queueSettingsUpdates(zip, updates);
|
|
308
309
|
const corePropsFile = zip.file("docProps/core.xml");
|
|
309
310
|
if (corePropsFile) {
|
|
310
|
-
const corePropsXml = await corePropsFile.async("
|
|
311
|
+
const corePropsXml = await corePropsFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
|
|
311
312
|
updates.set("docProps/core.xml", updateCoreProperties(corePropsXml, { updateModifiedDate: true }));
|
|
312
313
|
}
|
|
313
314
|
if ([...updates.keys()].some((path) => {
|
|
@@ -9,6 +9,7 @@ import { canReplayEditableImageRawXml } from "../imageRawXml.js";
|
|
|
9
9
|
import { serializeNonVisualDrawingNames } from "../nonVisualDrawingProps.js";
|
|
10
10
|
import { serializeBoundaryJoins } from "../reviewResolutionProvenance.js";
|
|
11
11
|
import { runHoldsPayload } from "../runPayload.js";
|
|
12
|
+
import { serializeEmptyRunProperties, serializePreviousRunProperties } from "../runPropertyPresence.js";
|
|
12
13
|
import { replayableShapeAlternateContent } from "../shapeAlternateContent.js";
|
|
13
14
|
import { requiredWrapPolygon, serializeWrapPolygon } from "../wrapPolygon.js";
|
|
14
15
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
@@ -52,7 +53,7 @@ function getUniqueId(id) {
|
|
|
52
53
|
}
|
|
53
54
|
function serializeRunPropertyChange(change) {
|
|
54
55
|
const previousRPrXml = serializeTextFormatting(change.previousFormatting) || "<w:rPr/>";
|
|
55
|
-
return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}${serializeBoundaryJoins(change.boundaryJoins)}>${previousRPrXml}</w:rPrChange>`;
|
|
56
|
+
return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}${serializeBoundaryJoins(change.boundaryJoins)}${serializePreviousRunProperties(change.previousFormatting)}>${previousRPrXml}</w:rPrChange>`;
|
|
56
57
|
}
|
|
57
58
|
function serializeRunProperties(formatting, propertyChanges) {
|
|
58
59
|
const propertyChange = getSingularRunPropertyChange(propertyChanges);
|
|
@@ -567,7 +568,7 @@ function serializeRun(run) {
|
|
|
567
568
|
const contentXml = serializeRunContent(content);
|
|
568
569
|
if (contentXml) parts.push(contentXml);
|
|
569
570
|
}
|
|
570
|
-
const attrs = serializePreservedAttributes(
|
|
571
|
+
const attrs = serializePreservedAttributes(serializeEmptyRunProperties(run), run.preservedAttributes);
|
|
571
572
|
return `<w:r${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}>${parts.join("")}</w:r>`;
|
|
572
573
|
}
|
|
573
574
|
/**
|
|
@@ -5,6 +5,7 @@ import { withPreservedChildren } from "../containerChildren.js";
|
|
|
5
5
|
import { TRANSITIONAL_NAME_BY_STRICT_NAME } from "../strictNames.gen.js";
|
|
6
6
|
import { TABLE_LOOK_FLAGS } from "../tableLook.js";
|
|
7
7
|
import { parseTableCellProperties, parseTableGrid, parseTableProperties, parseTablePropertyExceptions, parseTableRowProperties } from "../tableParser.js";
|
|
8
|
+
import { serializeEmptyRowProperties } from "../tableRowPropertyPresence.js";
|
|
8
9
|
import { OOXML_NAMESPACE_SCOPE, parseXml } from "../xmlParser.js";
|
|
9
10
|
import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
|
|
10
11
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
@@ -555,7 +556,7 @@ function serializeTableRow(row, serializeParagraph) {
|
|
|
555
556
|
carriers: carriersFor(cell),
|
|
556
557
|
xml: serializeTableCell(cell, serializeParagraph)
|
|
557
558
|
})), positionedChildren(row.preserved, row.bookmarks), preservedChild), 0));
|
|
558
|
-
const attrs = serializePreservedAttributes(
|
|
559
|
+
const attrs = serializePreservedAttributes(serializeEmptyRowProperties(row), row.preservedAttributes);
|
|
559
560
|
return `<w:tr${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}>${parts.join("")}</w:tr>`;
|
|
560
561
|
}
|
|
561
562
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeUtf8 } from "../../utils/textEncoding.js";
|
|
1
2
|
import { loadDocxArchive } from "./boundedArchive.js";
|
|
2
3
|
import { FOLIO_DOCX_XML_PATCH_PROPOSAL_PROFILE, InvalidFolioDocxXmlPatchProposalError, evaluateDocxXmlPatchProposal, parseFolioDocxXmlPatchProposal } from "./evaluateDocxXmlPatchProposal.js";
|
|
3
4
|
import { FOLIO_DOCX_CONFORMANCE_PROFILE, validateDocxConformance } from "./validateDocxConformance.js";
|
|
@@ -96,9 +97,8 @@ const applyReplacements = async ({ bytes, proposal }) => {
|
|
|
96
97
|
writeZipPart({
|
|
97
98
|
zip,
|
|
98
99
|
path: replacement.path,
|
|
99
|
-
data:
|
|
100
|
+
data: encodeUtf8(replacement.replacementXml),
|
|
100
101
|
options: {
|
|
101
|
-
binary: true,
|
|
102
102
|
date: current.date,
|
|
103
103
|
comment: current.comment,
|
|
104
104
|
unixPermissions: current.unixPermissions,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText } from "../../utils/textEncoding.js";
|
|
1
2
|
import { compressionRatioLimitFor, countCentralDirectoryRecords, createInflationBudget, exceedsCompressionRatio, getZipEntrySizes, inflateEntryWithinLimits } from "../archiveInflation.js";
|
|
2
3
|
import { FOLIO_XML_RESOURCE_LIMITS, assertXmlResourceLimits, createXmlPackageBudget } from "../xmlResourceLimits.js";
|
|
3
4
|
import { TaggedError } from "better-result";
|
|
@@ -170,7 +171,7 @@ const loadDocxArchive = async (bytes, options = {}) => {
|
|
|
170
171
|
async readEntryString(path) {
|
|
171
172
|
const content = await readEntry(path);
|
|
172
173
|
if (content === null) return null;
|
|
173
|
-
const xml =
|
|
174
|
+
const xml = decodeText(content, { ignoreBOM: true });
|
|
174
175
|
const lower = path.toLowerCase();
|
|
175
176
|
if (!lower.endsWith(".xml") && !lower.endsWith(".rels")) return xml;
|
|
176
177
|
const charged = countedParts.has(path);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeUtf8 } from "../../utils/textEncoding.js";
|
|
1
2
|
import { getDocxXmlSafetyIssue } from "../xmlSafety.js";
|
|
2
3
|
import { DocxArchiveError } from "./boundedArchive.js";
|
|
3
4
|
import { FolioDocxPackageInspectionError, inspectDocxPackage } from "./inspectDocxPackage.js";
|
|
@@ -264,7 +265,7 @@ const evaluateDocxXmlPatchProposal = async ({ bytes, proposal: rawProposal, allo
|
|
|
264
265
|
});
|
|
265
266
|
}
|
|
266
267
|
if (exceedsPartLowerBound || totalLimitReported) continue;
|
|
267
|
-
const replacementBytes =
|
|
268
|
+
const replacementBytes = encodeUtf8(replacement.replacementXml);
|
|
268
269
|
const exceedsEncodedPart = replacementBytes.byteLength > limits.maxPartBytes;
|
|
269
270
|
const nextEncodedTotalBytes = encodedTotalBytes + replacementBytes.byteLength;
|
|
270
271
|
if (exceedsEncodedPart) issues.push({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText } from "../../utils/textEncoding.js";
|
|
1
2
|
import { getAttributeAnyPrefix, getLocalName, parseXmlDocument } from "../xmlParser.js";
|
|
2
3
|
import { DocxArchiveError, loadDocxArchive } from "./boundedArchive.js";
|
|
3
4
|
import { Result, TaggedError } from "better-result";
|
|
@@ -33,7 +34,10 @@ const decodeXml = (bytes, part) => {
|
|
|
33
34
|
if (bytes.length >= 2 && (bytes[0] === 255 && bytes[1] === 254 || bytes[0] === 60 && bytes[1] === 0)) encoding = "utf-16le";
|
|
34
35
|
else if (bytes.length >= 2 && (bytes[0] === 254 && bytes[1] === 255 || bytes[0] === 0 && bytes[1] === 60)) encoding = "utf-16be";
|
|
35
36
|
const decoded = Result.try({
|
|
36
|
-
try: () =>
|
|
37
|
+
try: () => decodeText(bytes, {
|
|
38
|
+
encoding,
|
|
39
|
+
fatal: true
|
|
40
|
+
}),
|
|
37
41
|
catch: (cause) => new FolioDocxPackageInspectionError({
|
|
38
42
|
message: `Failed to decode XML package part "${part}"`,
|
|
39
43
|
code: "xml-decode-failed",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText } from "../../utils/textEncoding.js";
|
|
1
2
|
import { detectDocxConformanceClass } from "../conformance.js";
|
|
2
3
|
import { DOCX_CONTAINER_TYPES, detectDocxContainerType } from "../encryption/containerFormat.js";
|
|
3
4
|
import { DocxModelValidationError, validateFolioDocumentModel } from "../modelValidation.js";
|
|
@@ -131,7 +132,7 @@ const readPartForInspection = async (archive, part) => {
|
|
|
131
132
|
} catch (error) {
|
|
132
133
|
if (!(error instanceof XmlResourceLimitError) || error.limit !== "syntax") throw error;
|
|
133
134
|
const bytes = await archive.readEntryUint8(part);
|
|
134
|
-
return bytes === null ? null :
|
|
135
|
+
return bytes === null ? null : decodeText(bytes, { ignoreBOM: true });
|
|
135
136
|
}
|
|
136
137
|
};
|
|
137
138
|
const validateXmlParts = async (archive, report) => {
|
package/dist/docx/tableParser.js
CHANGED
|
@@ -11,10 +11,11 @@ import { captureSdtSiblingMarkers, parseSdtProperties } from "./sdtProperties.js
|
|
|
11
11
|
import { parseShading } from "./shadingParser.js";
|
|
12
12
|
import { findChildAnySpelling } from "./strictNames.js";
|
|
13
13
|
import { TABLE_LOOK_FLAGS } from "./tableLook.js";
|
|
14
|
+
import { isEmptyRowPropertiesAttribute, retainsEmptyRowProperties } from "./tableRowPropertyPresence.js";
|
|
14
15
|
import { parsePropertyChangeInfo, parseTrackedChangeInfo } from "./trackedChangeInfo.js";
|
|
15
16
|
import { percentageSpelling, transitionalSlotEncoding } from "./transitionalSpelling.js";
|
|
16
17
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
17
|
-
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findChild, findChildren, findWordprocessingChild, getAttribute, getAttributeByNamespaceUri, getLocalName, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute, parseTableMeasurementValue, selectAlternateContentBranch } from "./xmlParser.js";
|
|
18
|
+
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findChild, findChildren, findWordprocessingChild, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute, parseTableMeasurementValue, selectAlternateContentBranch } from "./xmlParser.js";
|
|
18
19
|
import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
|
|
19
20
|
//#region src/docx/tableParser.ts
|
|
20
21
|
/**
|
|
@@ -637,6 +638,8 @@ function parseTableRowProperties(trPrElement) {
|
|
|
637
638
|
context: formatting
|
|
638
639
|
});
|
|
639
640
|
if (preserved) formatting.preserved = preserved;
|
|
641
|
+
const children = getChildElements(trPrElement);
|
|
642
|
+
if (Object.keys(formatting).length === 0 && children.length > 0 && Object.keys(trPrElement.attributes ?? {}).every((name) => name === "xmlns" || name.startsWith("xmlns:")) && children.every((child) => WORDPROCESSINGML_NAMESPACE_URIS.has(child.namespaceUri ?? "") && REVISION_PROPERTY_CHILDREN.has(getLocalName(child.name)))) return void 0;
|
|
640
643
|
return withSourceXml(formatting, trPrElement);
|
|
641
644
|
}
|
|
642
645
|
/**
|
|
@@ -1099,7 +1102,7 @@ function parseTableRow(trElement, styles, theme, numbering, rels, media, options
|
|
|
1099
1102
|
const exceptionChanges = parseTablePropertyExceptionChanges(tblPrExElement, exceptions);
|
|
1100
1103
|
if (exceptionChanges !== void 0) row.tablePropertyExceptionChanges = exceptionChanges;
|
|
1101
1104
|
const trPrElement = findChild(trElement, "w", "trPr");
|
|
1102
|
-
const formatting = parseTableRowProperties(trPrElement);
|
|
1105
|
+
const formatting = parseTableRowProperties(trPrElement) ?? (trPrElement && retainsEmptyRowProperties(trElement) ? withSourceXml({}, trPrElement) : void 0);
|
|
1103
1106
|
if (formatting) row.formatting = formatting;
|
|
1104
1107
|
const rowPropChanges = parseTableRowPropertyChanges(trPrElement, formatting);
|
|
1105
1108
|
if (rowPropChanges !== void 0) row.propertyChanges = rowPropChanges;
|
|
@@ -1126,8 +1129,8 @@ function parseTableRow(trElement, styles, theme, numbering, rels, media, options
|
|
|
1126
1129
|
const remainingAttributes = attributeRemainder({
|
|
1127
1130
|
element: trElement,
|
|
1128
1131
|
modelled: NO_MODELLED_ATTRIBUTES
|
|
1129
|
-
});
|
|
1130
|
-
if (remainingAttributes) row.preservedAttributes = remainingAttributes;
|
|
1132
|
+
})?.filter((attribute) => !isEmptyRowPropertiesAttribute(attribute));
|
|
1133
|
+
if (remainingAttributes?.length) row.preservedAttributes = remainingAttributes;
|
|
1131
1134
|
return row;
|
|
1132
1135
|
}
|
|
1133
1136
|
/**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { XmlElement } from "./xmlParser.js";
|
|
3
|
+
//#region src/docx/tableRowPropertyPresence.d.ts
|
|
4
|
+
declare const EMPTY_ROW_PROPERTIES_ATTRIBUTE = "emptyRowProperties";
|
|
5
|
+
declare const retainsEmptyRowProperties: (element: XmlElement) => boolean;
|
|
6
|
+
declare const serializeEmptyRowProperties: (row: document_d_exports.TableRow) => string[];
|
|
7
|
+
declare const isEmptyRowPropertiesAttribute: ({ namespace, name }: Pick<document_d_exports.PreservedAttribute, "namespace" | "name">) => boolean;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EMPTY_ROW_PROPERTIES_ATTRIBUTE, isEmptyRowPropertiesAttribute, retainsEmptyRowProperties, serializeEmptyRowProperties };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { OOXML_NAMESPACES } from "./serializer/partNamespaces.js";
|
|
2
|
+
import { getAttributeByNamespaceUri } from "./xmlParser.js";
|
|
3
|
+
import { EMPTY_PROPERTY_SETS } from "@stll/docx-core/ops";
|
|
4
|
+
//#region src/docx/tableRowPropertyPresence.ts
|
|
5
|
+
const EMPTY_ROW_PROPERTIES_ATTRIBUTE = "emptyRowProperties";
|
|
6
|
+
const HISTORY_NAMESPACES = /* @__PURE__ */ new Set([OOXML_NAMESPACES.folio.uri]);
|
|
7
|
+
const retainsEmptyRowProperties = (element) => getAttributeByNamespaceUri(element, HISTORY_NAMESPACES, EMPTY_ROW_PROPERTIES_ATTRIBUTE) === EMPTY_PROPERTY_SETS.KEEP;
|
|
8
|
+
const serializeEmptyRowProperties = (row) => {
|
|
9
|
+
if (row.formatting === void 0 || row.structuralChange === void 0 && !row.propertyChanges?.length) return [];
|
|
10
|
+
const { sourceXml: _source, ...properties } = row.formatting;
|
|
11
|
+
return Object.keys(properties).length === 0 ? [`folio:${EMPTY_ROW_PROPERTIES_ATTRIBUTE}="${EMPTY_PROPERTY_SETS.KEEP}"`] : [];
|
|
12
|
+
};
|
|
13
|
+
const isEmptyRowPropertiesAttribute = ({ namespace, name }) => namespace === OOXML_NAMESPACES.folio.uri && name === "emptyRowProperties";
|
|
14
|
+
//#endregion
|
|
15
|
+
export { EMPTY_ROW_PROPERTIES_ATTRIBUTE, isEmptyRowPropertiesAttribute, retainsEmptyRowProperties, serializeEmptyRowProperties };
|
package/dist/docx/unzip.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { bytesToDataUrl } from "../utils/base64.js";
|
|
2
|
+
import { encodeUtf8 } from "../utils/textEncoding.js";
|
|
2
3
|
import { compressionRatioLimitFor, countCentralDirectoryRecords, createInflationBudget, exceedsCompressionRatio, getZipEntrySizes, inflateEntryWithinLimits, isStoredZipEntry } from "./archiveInflation.js";
|
|
3
4
|
import { DOCX_CONTAINER_TYPES, detectDocxContainerType } from "./encryption/containerFormat.js";
|
|
4
5
|
import { openDocxBuffer } from "./encryption/openEncryptedDocx.js";
|
|
@@ -286,7 +287,7 @@ const replaceRawDocxXmlParts = async (content, parts) => {
|
|
|
286
287
|
writeZipPart({
|
|
287
288
|
zip: content.originalZip,
|
|
288
289
|
path,
|
|
289
|
-
data: xmlContent
|
|
290
|
+
data: encodeUtf8(xmlContent)
|
|
290
291
|
});
|
|
291
292
|
identitiesChanged = true;
|
|
292
293
|
}
|
package/dist/docx/xmlEncoding.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { decodeText } from "../utils/textEncoding.js";
|
|
1
2
|
//#region src/docx/xmlEncoding.ts
|
|
2
3
|
/** Decode the UTF-8 and UTF-16 encodings XML processors must recognize. */
|
|
3
4
|
const decodeXmlBytes = (bytes) => {
|
|
4
|
-
if (bytes[0] === 255 && bytes[1] === 254) return
|
|
5
|
-
if (bytes[0] === 254 && bytes[1] === 255) return
|
|
6
|
-
if (bytes[0] === 60 && bytes[1] === 0 && bytes[2] === 63 && bytes[3] === 0) return
|
|
7
|
-
if (bytes[0] === 0 && bytes[1] === 60 && bytes[2] === 0 && bytes[3] === 63) return
|
|
5
|
+
if (bytes[0] === 255 && bytes[1] === 254) return decodeText(bytes.subarray(2), { encoding: "utf-16le" });
|
|
6
|
+
if (bytes[0] === 254 && bytes[1] === 255) return decodeText(bytes.subarray(2), { encoding: "utf-16be" });
|
|
7
|
+
if (bytes[0] === 60 && bytes[1] === 0 && bytes[2] === 63 && bytes[3] === 0) return decodeText(bytes, { encoding: "utf-16le" });
|
|
8
|
+
if (bytes[0] === 0 && bytes[1] === 60 && bytes[2] === 0 && bytes[3] === 63) return decodeText(bytes, { encoding: "utf-16be" });
|
|
8
9
|
const utf8Offset = bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0;
|
|
9
|
-
return
|
|
10
|
+
return decodeText(bytes.subarray(utf8Offset), { encoding: "utf-8" });
|
|
10
11
|
};
|
|
11
12
|
//#endregion
|
|
12
13
|
export { decodeXmlBytes };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { bytesToDataUrl } from "../utils/base64.js";
|
|
2
2
|
import { FONT_MAPPING } from "../utils/fontLoader.js";
|
|
3
3
|
import { parseFontFamilyList, resolveFontFamily } from "../utils/fontResolver.js";
|
|
4
|
+
import { decodeText } from "../utils/textEncoding.js";
|
|
4
5
|
//#region src/fonts/fontsourceFaces.ts
|
|
5
6
|
/**
|
|
6
7
|
* The subsets served, in resolution priority: a code point two subsets cover
|
|
@@ -78,7 +79,7 @@ const parseRangeToken = (token) => {
|
|
|
78
79
|
const parseRangeList = (declared) => declared.split(",").flatMap(parseRangeToken);
|
|
79
80
|
const parseDeclaredRanges = (bytes) => {
|
|
80
81
|
const ranges = /* @__PURE__ */ new Map();
|
|
81
|
-
const parsed = JSON.parse(
|
|
82
|
+
const parsed = JSON.parse(decodeText(bytes));
|
|
82
83
|
if (typeof parsed !== "object" || parsed === null) return ranges;
|
|
83
84
|
for (const [subset, declared] of Object.entries(parsed)) if (typeof declared === "string") ranges.set(subset, parseRangeList(declared));
|
|
84
85
|
return ranges;
|
package/dist/fonts/sfnt/parse.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText } from "../../utils/textEncoding.js";
|
|
1
2
|
import { SFNT_TABLE, SFNT_VERSION, fitsInView, readLocaOffsets, readSfntDirectory, readSfntVersion } from "./tables.js";
|
|
2
3
|
import { Result, TaggedError } from "better-result";
|
|
3
4
|
//#region src/fonts/sfnt/parse.ts
|
|
@@ -344,17 +345,13 @@ const sanitizePostScriptName = (raw) => {
|
|
|
344
345
|
return name.slice(0, MAX_POSTSCRIPT_NAME_LENGTH);
|
|
345
346
|
};
|
|
346
347
|
const decodeUtf16Be = (view, offset, length) => {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
return decodeText(new Uint8Array(view.buffer, view.byteOffset + offset, length - length % 2), {
|
|
349
|
+
encoding: "utf-16be",
|
|
350
|
+
ignoreBOM: true
|
|
351
|
+
});
|
|
350
352
|
};
|
|
351
353
|
const decodeMacRomanAscii = (view, offset, length) => {
|
|
352
|
-
|
|
353
|
-
for (let index = 0; index < length; index++) {
|
|
354
|
-
const code = view.getUint8(offset + index);
|
|
355
|
-
text += code < 128 ? String.fromCharCode(code) : "";
|
|
356
|
-
}
|
|
357
|
-
return text;
|
|
354
|
+
return decodeText(new Uint8Array(view.buffer, view.byteOffset + offset, length).filter((byte) => byte < 128), { encoding: "binary" });
|
|
358
355
|
};
|
|
359
356
|
/**
|
|
360
357
|
* name id 6, preferring the Windows UTF-16BE record over the Macintosh one.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeBinaryString } from "../../utils/textEncoding.js";
|
|
1
2
|
import { SFNT_TABLE, SFNT_VERSION, fitsInView, readLocaOffsets, readSfntDirectory } from "./tables.js";
|
|
2
3
|
import { Result, TaggedError, panic } from "better-result";
|
|
3
4
|
//#region src/fonts/sfnt/subset.ts
|
|
@@ -223,7 +224,7 @@ const assembleSfnt = (tables) => {
|
|
|
223
224
|
let dataOffset = 12 + directorySize;
|
|
224
225
|
let headOffset = -1;
|
|
225
226
|
for (const table of sorted) {
|
|
226
|
-
|
|
227
|
+
output.set(encodeBinaryString(table.tag), entry);
|
|
227
228
|
view.setUint32(entry + 4, checksumOf(table.data));
|
|
228
229
|
view.setUint32(entry + 8, dataOffset);
|
|
229
230
|
view.setUint32(entry + 12, table.data.byteLength);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeText } from "../../utils/textEncoding.js";
|
|
1
2
|
import { Result, TaggedError } from "better-result";
|
|
2
3
|
//#region src/fonts/sfnt/tables.ts
|
|
3
4
|
/**
|
|
@@ -65,9 +66,7 @@ const fitsInView = (view, offset, length) => Number.isInteger(offset) && Number.
|
|
|
65
66
|
/** The four-byte tag at `offset`, or `""` when it does not fit. */
|
|
66
67
|
const readTag = (view, offset) => {
|
|
67
68
|
if (!fitsInView(view, offset, TAG_LENGTH)) return "";
|
|
68
|
-
|
|
69
|
-
for (let index = 0; index < TAG_LENGTH; index++) tag += String.fromCharCode(view.getUint8(offset + index));
|
|
70
|
-
return tag;
|
|
69
|
+
return decodeText(new Uint8Array(view.buffer, view.byteOffset + offset, TAG_LENGTH), { encoding: "binary" });
|
|
71
70
|
};
|
|
72
71
|
/** The leading version word, or `undefined` when the buffer is shorter than it. */
|
|
73
72
|
const readSfntVersion = (bytes) => {
|
package/dist/fonts/sfnt/woff.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeBinaryString } from "../../utils/textEncoding.js";
|
|
1
2
|
import { SFNT_VERSION, readSfntVersion, readTag } from "./tables.js";
|
|
2
3
|
import { Result, TaggedError } from "better-result";
|
|
3
4
|
import { inflateSync } from "node:zlib";
|
|
@@ -76,7 +77,7 @@ const buildSfnt = (flavor, tables) => {
|
|
|
76
77
|
let entry = 12;
|
|
77
78
|
let dataOffset = 12 + directorySize;
|
|
78
79
|
for (const table of sorted) {
|
|
79
|
-
|
|
80
|
+
output.set(encodeBinaryString(table.tag), entry);
|
|
80
81
|
view.setUint32(entry + 4, table.checksum);
|
|
81
82
|
view.setUint32(entry + 8, dataOffset);
|
|
82
83
|
view.setUint32(entry + 12, table.data.byteLength);
|
|
@@ -362,6 +362,7 @@ const messages = { "folio": {
|
|
|
362
362
|
"previous": "النتيجة السابقة",
|
|
363
363
|
"previousShortcut": "النتيجة السابقة (Shift+Enter)",
|
|
364
364
|
"replaceAll": "استبدال الكل",
|
|
365
|
+
"replaceAllSummary": "تم استبدال {replacedCount} وتخطي {skippedCount}",
|
|
365
366
|
"replaceCurrent": "استبدال النتيجة الحالية",
|
|
366
367
|
"replacePlaceholder": "نص الاستبدال...",
|
|
367
368
|
"replaceText": "نص الاستبدال",
|