@stll/folio-core 0.8.0 → 0.10.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 +39 -0
- package/dist/ai-edits/apply.js +18 -4
- package/dist/ai-edits/headless.d.ts +73 -6
- package/dist/ai-edits/headless.js +299 -60
- package/dist/ai-edits/index.d.ts +3 -3
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/snapshot.js +40 -3
- package/dist/ai-edits/types.d.ts +2 -1
- package/dist/compat/eigenpal.d.ts +6 -4
- package/dist/compat/eigenpal.js +5 -3
- package/dist/controller/latestRequestGate.d.ts +13 -0
- package/dist/controller/latestRequestGate.js +16 -0
- package/dist/controller/layoutPipeline.js +13 -1
- package/dist/document-operations.d.ts +20 -4
- package/dist/document-operations.js +36 -15
- package/dist/document-stories.d.ts +10 -0
- package/dist/document-stories.js +27 -0
- package/dist/docx/blockContentParser.js +2 -2
- package/dist/docx/commentParser.js +1 -1
- package/dist/docx/compatibility.d.ts +3 -7
- package/dist/docx/compatibility.js +0 -11
- package/dist/docx/corePropertiesParser.d.ts +8 -0
- package/dist/docx/corePropertiesParser.js +53 -0
- package/dist/docx/encryption/agileDecryption.js +1 -1
- package/dist/docx/encryption/encryptionInfo.js +1 -1
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/fontTableParser.d.ts +6 -0
- package/dist/docx/fontTableParser.js +72 -0
- package/dist/docx/groupDrawingParser.js +7 -2
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/index.d.ts +2 -1
- package/dist/docx/index.js +2 -1
- package/dist/docx/metadataPrivacy.d.ts +40 -0
- package/dist/docx/metadataPrivacy.js +131 -0
- package/dist/docx/normalizeBaseDirection.js +1 -1
- package/dist/docx/numberingParser.js +1 -0
- package/dist/docx/paragraphParser.js +12 -1
- package/dist/docx/parser.d.ts +1 -1
- package/dist/docx/parser.js +16 -10
- package/dist/docx/rezip.d.ts +5 -4
- package/dist/docx/rezip.js +76 -13
- package/dist/docx/runConsolidator.js +4 -0
- package/dist/docx/runParser.js +19 -1
- package/dist/docx/selectiveSave.js +3 -3
- package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
- package/dist/docx/serializer/fontTableSerializer.js +26 -0
- package/dist/docx/serializer/headerFooterSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +4 -0
- package/dist/docx/serializer/runSerializer.js +7 -0
- package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
- package/dist/docx/serializer/settingsSerializer.js +16 -0
- package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
- package/dist/docx/serializer/stylesSerializer.js +56 -0
- package/dist/docx/serializer/tableSerializer.js +25 -26
- package/dist/docx/serializer/themeSerializer.d.ts +6 -0
- package/dist/docx/serializer/themeSerializer.js +36 -0
- package/dist/docx/settingsParser.js +46 -0
- package/dist/docx/styleParser.js +26 -1
- package/dist/docx/tableParser.js +11 -1
- package/dist/docx/vmlImageParser.js +1 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
- package/dist/i18n/messages/catalogs.gen.js +5910 -5910
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +6 -1
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +52 -14
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-engine/index.js +36 -28
- package/dist/layout-engine/measure/cache.js +6 -3
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.d.ts +29 -0
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +60 -0
- package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
- package/dist/layout-engine/measure/index.d.ts +2 -1
- package/dist/layout-engine/measure/index.js +2 -1
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
- package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
- package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
- package/dist/layout-engine/measure/lineBreaks.js +11 -18
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +12 -6
- package/dist/layout-engine/measure/measureBlocks.d.ts +1 -2
- package/dist/layout-engine/measure/measureBlocks.js +6 -36
- package/dist/layout-engine/measure/measureContainer.js +32 -9
- package/dist/layout-engine/measure/measureHelpers.js +5 -2
- package/dist/layout-engine/measure/measureParagraph.js +332 -73
- package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
- package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
- package/dist/layout-engine/measure/measureWorker.js +8 -19
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
- package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
- package/dist/layout-engine/measure/tableCellFloating.js +51 -37
- package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
- package/dist/layout-engine/measure/tableCellFlow.js +73 -0
- package/dist/layout-engine/measure/tableCellGrid.js +1 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +6 -1
- package/dist/layout-engine/renderedBreakReconciliation.js +34 -11
- package/dist/layout-engine/tableRowBreak.d.ts +5 -2
- package/dist/layout-engine/tableRowBreak.js +62 -29
- package/dist/layout-engine/types.d.ts +43 -8
- package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
- package/dist/layout-painter/anchoredImagePosition.js +95 -0
- package/dist/layout-painter/borderStroke.d.ts +23 -0
- package/dist/layout-painter/borderStroke.js +39 -0
- package/dist/layout-painter/renderImage.d.ts +5 -4
- package/dist/layout-painter/renderImage.js +18 -4
- package/dist/layout-painter/renderPage.d.ts +2 -27
- package/dist/layout-painter/renderPage.js +13 -99
- package/dist/layout-painter/renderParagraph.js +41 -23
- package/dist/layout-painter/renderTable.d.ts +2 -0
- package/dist/layout-painter/renderTable.js +223 -43
- package/dist/managers/DocumentLoaderManager.d.ts +1 -1
- package/dist/managers/DocumentLoaderManager.js +2 -2
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +22 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
- package/dist/prosemirror/conversion/effectiveTableCellFormatting.d.ts +62 -0
- package/dist/prosemirror/conversion/effectiveTableCellFormatting.js +131 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +34 -18
- package/dist/prosemirror/conversion/toProseDoc.js +81 -77
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +7 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
- package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +3 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +6 -1
- package/dist/prosemirror/schema/nodes.d.ts +15 -12
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
- package/dist/prosemirror/utils/tabCalculator.js +12 -10
- package/dist/prosemirror/validation.js +4 -1
- package/dist/redline.d.ts +26 -11
- package/dist/redline.js +107 -64
- package/dist/server.d.ts +9 -5
- package/dist/server.js +8 -4
- package/dist/style-sets/extract.d.ts +35 -0
- package/dist/style-sets/extract.js +123 -0
- package/dist/style-sets/stellaStyle.d.ts +13 -0
- package/dist/style-sets/stellaStyle.js +516 -0
- package/dist/style-sets/types.d.ts +31 -0
- package/dist/style-sets/types.js +5 -0
- package/dist/utils/createDocument.d.ts +12 -2
- package/dist/utils/createDocument.js +42 -31
- package/dist/utils/fontResolver.js +6 -6
- package/dist/utils/formatToStyle.js +1 -1
- package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
- package/dist/utils/paragraphFormattingMerge.js +14 -4
- package/dist/version-comparison.d.ts +65 -11
- package/dist/version-comparison.js +187 -29
- package/package.json +5 -1
- package/dist/docx/capabilities.d.ts +0 -41
- package/dist/docx/capabilities.js +0 -322
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { findChild, findChildren, getAttribute, parseXmlDocument } from "./xmlParser.js";
|
|
2
|
+
//#region src/docx/fontTableParser.ts
|
|
3
|
+
const FONT_FAMILIES = [
|
|
4
|
+
"decorative",
|
|
5
|
+
"modern",
|
|
6
|
+
"roman",
|
|
7
|
+
"script",
|
|
8
|
+
"swiss",
|
|
9
|
+
"auto"
|
|
10
|
+
];
|
|
11
|
+
const FONT_PITCHES = [
|
|
12
|
+
"default",
|
|
13
|
+
"fixed",
|
|
14
|
+
"variable"
|
|
15
|
+
];
|
|
16
|
+
const parseFontTable = (xml) => {
|
|
17
|
+
if (!xml) return;
|
|
18
|
+
const root = parseXmlDocument(xml);
|
|
19
|
+
if (!root) return;
|
|
20
|
+
const fonts = [];
|
|
21
|
+
for (const element of findChildren(root, "w", "font")) {
|
|
22
|
+
const font = parseFont(element);
|
|
23
|
+
if (font) fonts.push(font);
|
|
24
|
+
}
|
|
25
|
+
return fonts.length > 0 ? { fonts } : void 0;
|
|
26
|
+
};
|
|
27
|
+
const parseFont = (element) => {
|
|
28
|
+
const name = getAttribute(element, "w", "name");
|
|
29
|
+
if (!name) return;
|
|
30
|
+
const font = { name };
|
|
31
|
+
assignValue(font, "altName", childValue(element, "altName"));
|
|
32
|
+
assignValue(font, "panose1", childValue(element, "panose1"));
|
|
33
|
+
assignValue(font, "charset", childValue(element, "charset"));
|
|
34
|
+
const family = childValue(element, "family");
|
|
35
|
+
if (family && isFontFamily(family)) font.family = family;
|
|
36
|
+
const pitch = childValue(element, "pitch");
|
|
37
|
+
if (pitch && isFontPitch(pitch)) font.pitch = pitch;
|
|
38
|
+
const sig = findChild(element, "w", "sig");
|
|
39
|
+
if (sig) {
|
|
40
|
+
const parsed = {};
|
|
41
|
+
assignSignatureValue(parsed, "usb0", getAttribute(sig, "w", "usb0") ?? void 0);
|
|
42
|
+
assignSignatureValue(parsed, "usb1", getAttribute(sig, "w", "usb1") ?? void 0);
|
|
43
|
+
assignSignatureValue(parsed, "usb2", getAttribute(sig, "w", "usb2") ?? void 0);
|
|
44
|
+
assignSignatureValue(parsed, "usb3", getAttribute(sig, "w", "usb3") ?? void 0);
|
|
45
|
+
assignSignatureValue(parsed, "csb0", getAttribute(sig, "w", "csb0") ?? void 0);
|
|
46
|
+
assignSignatureValue(parsed, "csb1", getAttribute(sig, "w", "csb1") ?? void 0);
|
|
47
|
+
if (Object.values(parsed).some((value) => value !== void 0)) font.sig = parsed;
|
|
48
|
+
}
|
|
49
|
+
assignValue(font, "embedRegular", relationshipId(element, "embedRegular"));
|
|
50
|
+
assignValue(font, "embedBold", relationshipId(element, "embedBold"));
|
|
51
|
+
assignValue(font, "embedItalic", relationshipId(element, "embedItalic"));
|
|
52
|
+
assignValue(font, "embedBoldItalic", relationshipId(element, "embedBoldItalic"));
|
|
53
|
+
return font;
|
|
54
|
+
};
|
|
55
|
+
const childValue = (element, name) => {
|
|
56
|
+
const child = findChild(element, "w", name);
|
|
57
|
+
return child ? getAttribute(child, "w", "val") ?? void 0 : void 0;
|
|
58
|
+
};
|
|
59
|
+
const relationshipId = (element, name) => {
|
|
60
|
+
const child = findChild(element, "w", name);
|
|
61
|
+
return child ? getAttribute(child, "r", "id") ?? void 0 : void 0;
|
|
62
|
+
};
|
|
63
|
+
const assignValue = (font, key, value) => {
|
|
64
|
+
if (value !== void 0) font[key] = value;
|
|
65
|
+
};
|
|
66
|
+
const assignSignatureValue = (signature, key, value) => {
|
|
67
|
+
if (value !== void 0) signature[key] = value;
|
|
68
|
+
};
|
|
69
|
+
const isFontFamily = (value) => FONT_FAMILIES.some((family) => family === value);
|
|
70
|
+
const isFontPitch = (value) => FONT_PITCHES.some((pitch) => pitch === value);
|
|
71
|
+
//#endregion
|
|
72
|
+
export { parseFontTable };
|
|
@@ -37,7 +37,10 @@ const colorFrom = (parent, fallback) => {
|
|
|
37
37
|
const value = getAttribute(parent, "w", "val");
|
|
38
38
|
if (value && HEX_COLOR.test(value)) return value.toUpperCase();
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
if (findChildByLocalName(parent, "noFill")) return "none";
|
|
41
|
+
const srgb = findChildByLocalName(findChildByLocalName(parent, "solidFill"), "srgbClr");
|
|
42
|
+
const referencedSrgb = findChildByLocalName(parent, "srgbClr");
|
|
43
|
+
const value = getAttribute(srgb ?? referencedSrgb, null, "val");
|
|
41
44
|
if (value && HEX_COLOR.test(value)) return value.toUpperCase();
|
|
42
45
|
return fallback;
|
|
43
46
|
};
|
|
@@ -80,9 +83,11 @@ const renderGeometry = (wsp) => {
|
|
|
80
83
|
const { x, y, width, height } = childTransform(wsp);
|
|
81
84
|
if (width <= 0 || height <= 0) return "";
|
|
82
85
|
const spPr = findChildByLocalName(wsp, "spPr");
|
|
86
|
+
const style = findChildByLocalName(wsp, "style");
|
|
87
|
+
const styleStroke = colorFrom(findChildByLocalName(style, "lnRef"), "none");
|
|
83
88
|
const fill = colorFrom(spPr, "none");
|
|
84
89
|
const line = findChildByLocalName(spPr, "ln");
|
|
85
|
-
const stroke = colorFrom(line,
|
|
90
|
+
const stroke = colorFrom(line, styleStroke);
|
|
86
91
|
const strokeWidth = line ? parseNumericAttribute(line, null, "w") ?? DEFAULT_LINE_WIDTH_EMU : 0;
|
|
87
92
|
const paths = findAllDeep(findChildByLocalName(spPr, "custGeom"), "a", "path");
|
|
88
93
|
if (paths.length === 0) return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${fill === "none" ? "none" : `#${fill}`}" stroke="${stroke === "none" ? "none" : `#${stroke}`}" stroke-width="${strokeWidth}"/>`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { collectXmlnsDeclarations, parseXml } from "./xmlParser.js";
|
|
2
2
|
import { parseWatermark } from "./watermarkParser.js";
|
|
3
3
|
import { parseFooterReference, parseFooterReferences, parseHeaderReference, parseHeaderReferences } from "./headerFooterRefParser.js";
|
|
4
|
-
import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
|
|
5
4
|
import { parseBlockContent } from "./blockContentParser.js";
|
|
5
|
+
import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
|
|
6
6
|
//#region src/docx/headerFooterParser.ts
|
|
7
7
|
/**
|
|
8
8
|
* Parse a header XML file (word/header*.xml)
|
package/dist/docx/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getCachedNumberingMap } from "./numberingParser.js";
|
|
2
2
|
import { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, DocxEncryptionErrorCode, isDocxEncryptionError } from "./encryption/errors.js";
|
|
3
3
|
import { DecryptDocxOptions, DecryptDocxResult, decryptDocxIfNeeded, openDocxBuffer } from "./encryption/openEncryptedDocx.js";
|
|
4
|
-
|
|
4
|
+
import { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, FolioDocumentPrivacyOptions, FolioDocumentPrivacyReport, FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, RewriteDocxMetadataPrivacyResult, isFolioDocumentPrivacyTransform, rewriteDocxMetadataPrivacy } from "./metadataPrivacy.js";
|
|
5
|
+
export { DOCX_ENCRYPTION_ERROR_CODES, type DecryptDocxOptions, type DecryptDocxResult, DocxEncryptionError, type DocxEncryptionErrorCode, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, type FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, type FolioDocumentPrivacyOptions, type FolioDocumentPrivacyReport, type FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, type RewriteDocxMetadataPrivacyResult, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, isFolioDocumentPrivacyTransform, openDocxBuffer, rewriteDocxMetadataPrivacy };
|
package/dist/docx/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getCachedNumberingMap } from "./numberingParser.js";
|
|
2
2
|
import { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, isDocxEncryptionError } from "./encryption/errors.js";
|
|
3
3
|
import { decryptDocxIfNeeded, openDocxBuffer } from "./encryption/openEncryptedDocx.js";
|
|
4
|
-
|
|
4
|
+
import { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, isFolioDocumentPrivacyTransform, rewriteDocxMetadataPrivacy } from "./metadataPrivacy.js";
|
|
5
|
+
export { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError, FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, decryptDocxIfNeeded, getCachedNumberingMap, isDocxEncryptionError, isFolioDocumentPrivacyTransform, openDocxBuffer, rewriteDocxMetadataPrivacy };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/docx/metadataPrivacy.d.ts
|
|
2
|
+
declare const FOLIO_DOCUMENT_METADATA_PROPERTIES: readonly ["title", "subject", "creator", "keywords", "description", "lastModifiedBy", "revision", "created", "modified"];
|
|
3
|
+
type FolioDocumentMetadataProperty = (typeof FOLIO_DOCUMENT_METADATA_PROPERTIES)[number];
|
|
4
|
+
declare const FOLIO_DOCUMENT_PRIVACY_TRANSFORMS: readonly ["remove-attribution", "remove-timestamps", "remove-descriptive-metadata"];
|
|
5
|
+
type FolioDocumentPrivacyTransform = (typeof FOLIO_DOCUMENT_PRIVACY_TRANSFORMS)[number];
|
|
6
|
+
declare const isFolioDocumentPrivacyTransform: (value: unknown) => value is FolioDocumentPrivacyTransform;
|
|
7
|
+
type FolioDocumentPrivacyOptions = {
|
|
8
|
+
transforms: readonly FolioDocumentPrivacyTransform[];
|
|
9
|
+
};
|
|
10
|
+
type FolioDocumentPrivacyReport = {
|
|
11
|
+
appliedTransforms: FolioDocumentPrivacyTransform[];
|
|
12
|
+
removedMetadataProperties: FolioDocumentMetadataProperty[];
|
|
13
|
+
};
|
|
14
|
+
type RewriteDocxMetadataPrivacyResult = {
|
|
15
|
+
buffer: ArrayBuffer;
|
|
16
|
+
privacyReport: FolioDocumentPrivacyReport;
|
|
17
|
+
};
|
|
18
|
+
declare const InvalidFolioDocumentPrivacyOptionsError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocumentPrivacyOptionsError", {
|
|
19
|
+
message: string;
|
|
20
|
+
receivedValue: unknown;
|
|
21
|
+
}>;
|
|
22
|
+
declare class InvalidFolioDocumentPrivacyOptionsError extends InvalidFolioDocumentPrivacyOptionsError_base {}
|
|
23
|
+
declare const FolioDocumentPrivacyArchiveError_base: import("better-result").TaggedErrorClass<"FolioDocumentPrivacyArchiveError", {
|
|
24
|
+
message: string;
|
|
25
|
+
reason: "input-too-large" | "load-failed" | "too-many-entries" | "core-properties-too-large";
|
|
26
|
+
cause?: unknown;
|
|
27
|
+
}>;
|
|
28
|
+
declare class FolioDocumentPrivacyArchiveError extends FolioDocumentPrivacyArchiveError_base {}
|
|
29
|
+
declare const PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM: {
|
|
30
|
+
readonly "remove-attribution": readonly ["creator", "lastModifiedBy"];
|
|
31
|
+
readonly "remove-timestamps": readonly ["created", "modified"];
|
|
32
|
+
readonly "remove-descriptive-metadata": readonly ["title", "subject", "keywords", "description"];
|
|
33
|
+
};
|
|
34
|
+
declare const resolveFolioDocumentPrivacyTransforms: (transforms: unknown) => FolioDocumentPrivacyTransform[];
|
|
35
|
+
/** Rewrite selected package metadata fields without changing other package parts. */
|
|
36
|
+
declare const rewriteDocxMetadataPrivacy: (buffer: ArrayBuffer, {
|
|
37
|
+
transforms
|
|
38
|
+
}: FolioDocumentPrivacyOptions) => Promise<RewriteDocxMetadataPrivacyResult>;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentMetadataProperty, FolioDocumentPrivacyArchiveError, FolioDocumentPrivacyOptions, FolioDocumentPrivacyReport, FolioDocumentPrivacyTransform, InvalidFolioDocumentPrivacyOptionsError, PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM, RewriteDocxMetadataPrivacyResult, isFolioDocumentPrivacyTransform, resolveFolioDocumentPrivacyTransforms, rewriteDocxMetadataPrivacy };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { elementToXml, getLocalName, parseXmlDocument } from "./xmlParser.js";
|
|
2
|
+
import { TaggedError } from "better-result";
|
|
3
|
+
import JSZip from "jszip";
|
|
4
|
+
//#region src/docx/metadataPrivacy.ts
|
|
5
|
+
const FOLIO_DOCUMENT_METADATA_PROPERTIES = Object.freeze([
|
|
6
|
+
"title",
|
|
7
|
+
"subject",
|
|
8
|
+
"creator",
|
|
9
|
+
"keywords",
|
|
10
|
+
"description",
|
|
11
|
+
"lastModifiedBy",
|
|
12
|
+
"revision",
|
|
13
|
+
"created",
|
|
14
|
+
"modified"
|
|
15
|
+
]);
|
|
16
|
+
const isFolioDocumentMetadataProperty = (value) => FOLIO_DOCUMENT_METADATA_PROPERTIES.some((property) => property === value);
|
|
17
|
+
const FOLIO_DOCUMENT_PRIVACY_TRANSFORMS = Object.freeze([
|
|
18
|
+
"remove-attribution",
|
|
19
|
+
"remove-timestamps",
|
|
20
|
+
"remove-descriptive-metadata"
|
|
21
|
+
]);
|
|
22
|
+
const isFolioDocumentPrivacyTransform = (value) => FOLIO_DOCUMENT_PRIVACY_TRANSFORMS.some((transform) => transform === value);
|
|
23
|
+
var InvalidFolioDocumentPrivacyOptionsError = class extends TaggedError("InvalidFolioDocumentPrivacyOptionsError")() {};
|
|
24
|
+
var FolioDocumentPrivacyArchiveError = class extends TaggedError("FolioDocumentPrivacyArchiveError")() {};
|
|
25
|
+
const PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM = {
|
|
26
|
+
"remove-attribution": ["creator", "lastModifiedBy"],
|
|
27
|
+
"remove-timestamps": ["created", "modified"],
|
|
28
|
+
"remove-descriptive-metadata": [
|
|
29
|
+
"title",
|
|
30
|
+
"subject",
|
|
31
|
+
"keywords",
|
|
32
|
+
"description"
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
const resolveFolioDocumentPrivacyTransforms = (transforms) => {
|
|
36
|
+
if (!Array.isArray(transforms) || transforms.some((transform) => !isFolioDocumentPrivacyTransform(transform))) throw new InvalidFolioDocumentPrivacyOptionsError({
|
|
37
|
+
message: "Document privacy received an unrecognized transform",
|
|
38
|
+
receivedValue: transforms
|
|
39
|
+
});
|
|
40
|
+
const requested = new Set(transforms);
|
|
41
|
+
return FOLIO_DOCUMENT_PRIVACY_TRANSFORMS.filter((transform) => requested.has(transform));
|
|
42
|
+
};
|
|
43
|
+
const XML_DECLARATION_PATTERN = /^\s*<\?xml[^?]*\?>/u;
|
|
44
|
+
const MAX_INPUT_BYTES = 50 * 1024 * 1024;
|
|
45
|
+
const MAX_ARCHIVE_ENTRIES = 5e3;
|
|
46
|
+
const MAX_CORE_PROPERTIES_BYTES = 1024 * 1024;
|
|
47
|
+
const loadPrivacyArchive = async (buffer) => {
|
|
48
|
+
if (buffer.byteLength > MAX_INPUT_BYTES) throw new FolioDocumentPrivacyArchiveError({
|
|
49
|
+
message: "Document privacy input exceeded the compressed-size limit",
|
|
50
|
+
reason: "input-too-large"
|
|
51
|
+
});
|
|
52
|
+
let zip;
|
|
53
|
+
try {
|
|
54
|
+
zip = await JSZip.loadAsync(buffer);
|
|
55
|
+
} catch (cause) {
|
|
56
|
+
throw new FolioDocumentPrivacyArchiveError({
|
|
57
|
+
message: "Document privacy input is not a readable package",
|
|
58
|
+
reason: "load-failed",
|
|
59
|
+
cause
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (Object.values(zip.files).length > MAX_ARCHIVE_ENTRIES) throw new FolioDocumentPrivacyArchiveError({
|
|
63
|
+
message: "Document privacy input exceeded the package-entry limit",
|
|
64
|
+
reason: "too-many-entries"
|
|
65
|
+
});
|
|
66
|
+
const coreProperties = zip.file("docProps/core.xml");
|
|
67
|
+
if (!coreProperties) return zip;
|
|
68
|
+
const data = "_data" in coreProperties ? coreProperties._data : void 0;
|
|
69
|
+
const declaredBytes = typeof data === "object" && data !== null && "uncompressedSize" in data ? data.uncompressedSize : void 0;
|
|
70
|
+
if (typeof declaredBytes !== "number" || declaredBytes > MAX_CORE_PROPERTIES_BYTES) throw new FolioDocumentPrivacyArchiveError({
|
|
71
|
+
message: "Document privacy core properties exceeded the part-size limit",
|
|
72
|
+
reason: "core-properties-too-large"
|
|
73
|
+
});
|
|
74
|
+
return zip;
|
|
75
|
+
};
|
|
76
|
+
const rewriteCorePropertiesPrivacy = (xml, transforms) => {
|
|
77
|
+
const root = parseXmlDocument(xml);
|
|
78
|
+
if (!root?.elements) return {
|
|
79
|
+
xml,
|
|
80
|
+
removedMetadataProperties: []
|
|
81
|
+
};
|
|
82
|
+
const propertiesToRemove = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const transform of transforms) for (const property of PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM[transform]) propertiesToRemove.add(property);
|
|
84
|
+
const removedPropertySet = /* @__PURE__ */ new Set();
|
|
85
|
+
root.elements = root.elements.filter((element) => {
|
|
86
|
+
if (element.type !== "element") return true;
|
|
87
|
+
const property = getLocalName(element.name ?? "");
|
|
88
|
+
if (!isFolioDocumentMetadataProperty(property)) return true;
|
|
89
|
+
if (!propertiesToRemove.has(property)) return true;
|
|
90
|
+
removedPropertySet.add(property);
|
|
91
|
+
return false;
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
xml: `${xml.match(XML_DECLARATION_PATTERN)?.at(0) ?? ""}${elementToXml(root)}`,
|
|
95
|
+
removedMetadataProperties: FOLIO_DOCUMENT_METADATA_PROPERTIES.filter((property) => removedPropertySet.has(property))
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
/** Rewrite selected package metadata fields without changing other package parts. */
|
|
99
|
+
const rewriteDocxMetadataPrivacy = async (buffer, { transforms }) => {
|
|
100
|
+
const appliedTransforms = resolveFolioDocumentPrivacyTransforms(transforms);
|
|
101
|
+
const zip = await loadPrivacyArchive(buffer);
|
|
102
|
+
const coreProperties = zip.file("docProps/core.xml");
|
|
103
|
+
if (!coreProperties) return {
|
|
104
|
+
buffer,
|
|
105
|
+
privacyReport: {
|
|
106
|
+
appliedTransforms,
|
|
107
|
+
removedMetadataProperties: []
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const rewritten = rewriteCorePropertiesPrivacy(await coreProperties.async("text"), appliedTransforms);
|
|
111
|
+
if (rewritten.removedMetadataProperties.length === 0) return {
|
|
112
|
+
buffer,
|
|
113
|
+
privacyReport: {
|
|
114
|
+
appliedTransforms,
|
|
115
|
+
removedMetadataProperties: []
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
zip.file("docProps/core.xml", rewritten.xml);
|
|
119
|
+
return {
|
|
120
|
+
buffer: await zip.generateAsync({
|
|
121
|
+
type: "arraybuffer",
|
|
122
|
+
compression: "DEFLATE"
|
|
123
|
+
}),
|
|
124
|
+
privacyReport: {
|
|
125
|
+
appliedTransforms,
|
|
126
|
+
removedMetadataProperties: rewritten.removedMetadataProperties
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
export { FOLIO_DOCUMENT_METADATA_PROPERTIES, FOLIO_DOCUMENT_PRIVACY_TRANSFORMS, FolioDocumentPrivacyArchiveError, InvalidFolioDocumentPrivacyOptionsError, PRIVATE_METADATA_PROPERTIES_BY_TRANSFORM, isFolioDocumentPrivacyTransform, resolveFolioDocumentPrivacyTransforms, rewriteDocxMetadataPrivacy };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { detectBaseDirection } from "../utils/baseDirection.js";
|
|
2
1
|
import { createStyleResolver } from "../prosemirror/styles/styleResolver.js";
|
|
2
|
+
import { detectBaseDirection } from "../utils/baseDirection.js";
|
|
3
3
|
//#region src/docx/normalizeBaseDirection.ts
|
|
4
4
|
const runText = (run) => {
|
|
5
5
|
let text = "";
|
|
@@ -603,6 +603,7 @@ function computeListRendering(numPr, numbering) {
|
|
|
603
603
|
const markerFont = level.rPr?.fontFamily?.ascii || level.rPr?.fontFamily?.hAnsi;
|
|
604
604
|
if (markerFont) rendering.markerFontFamily = markerFont;
|
|
605
605
|
if (level.rPr?.fontSize) rendering.markerFontSize = level.rPr.fontSize / 2;
|
|
606
|
+
if (level.rPr?.bold !== void 0) rendering.markerBold = level.rPr.bold;
|
|
606
607
|
if (level.rPr?.allCaps) rendering.markerAllCaps = true;
|
|
607
608
|
if (level.lvlJc) rendering.markerAlignment = level.lvlJc;
|
|
608
609
|
if (level.suffix) rendering.markerSuffix = level.suffix;
|
|
@@ -164,12 +164,18 @@ function collectFirstParagraphPropertyChildren(pPr) {
|
|
|
164
164
|
case "keepNext":
|
|
165
165
|
children.keepNext ??= child;
|
|
166
166
|
break;
|
|
167
|
+
case "kinsoku":
|
|
168
|
+
children.kinsoku ??= child;
|
|
169
|
+
break;
|
|
167
170
|
case "numPr":
|
|
168
171
|
children.numPr ??= child;
|
|
169
172
|
break;
|
|
170
173
|
case "outlineLvl":
|
|
171
174
|
children.outlineLvl ??= child;
|
|
172
175
|
break;
|
|
176
|
+
case "overflowPunct":
|
|
177
|
+
children.overflowPunct ??= child;
|
|
178
|
+
break;
|
|
173
179
|
case "pageBreakBefore":
|
|
174
180
|
children.pageBreakBefore ??= child;
|
|
175
181
|
break;
|
|
@@ -226,6 +232,10 @@ function parseParagraphProperties(pPr, theme, styles) {
|
|
|
226
232
|
if (!pPr) return;
|
|
227
233
|
const formatting = {};
|
|
228
234
|
const propertyChildren = collectFirstParagraphPropertyChildren(pPr);
|
|
235
|
+
const kinsoku = propertyChildren.kinsoku;
|
|
236
|
+
if (kinsoku) formatting.kinsoku = parseBooleanElement(kinsoku);
|
|
237
|
+
const overflowPunct = propertyChildren.overflowPunct;
|
|
238
|
+
if (overflowPunct) formatting.overflowPunctuation = parseBooleanElement(overflowPunct);
|
|
229
239
|
const jc = propertyChildren.jc;
|
|
230
240
|
if (jc) {
|
|
231
241
|
const val = narrowEnum(getAttribute(jc, "w", "val"), ParagraphAlignmentSchema);
|
|
@@ -525,7 +535,7 @@ function isTrackedChangeWrapperChild(content) {
|
|
|
525
535
|
return content.type === "run" || content.type === "hyperlink";
|
|
526
536
|
}
|
|
527
537
|
function isInlineSdtContent(content) {
|
|
528
|
-
return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "mathEquation";
|
|
538
|
+
return content.type === "run" || content.type === "hyperlink" || content.type === "simpleField" || content.type === "complexField" || content.type === "inlineSdt" || content.type === "insertion" || content.type === "deletion" || content.type === "mathEquation";
|
|
529
539
|
}
|
|
530
540
|
function pushTrackedChangeWrapper({ contents, type, info, content, preserveEmpty = false }) {
|
|
531
541
|
if (content.length === 0 && !preserveEmpty) return;
|
|
@@ -981,6 +991,7 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
981
991
|
const markerFont = level.rPr?.fontFamily?.ascii || level.rPr?.fontFamily?.hAnsi;
|
|
982
992
|
if (markerFont) listRendering.markerFontFamily = markerFont;
|
|
983
993
|
if (level.rPr?.fontSize) listRendering.markerFontSize = level.rPr.fontSize / 2;
|
|
994
|
+
if (level.rPr?.bold !== void 0) listRendering.markerBold = level.rPr.bold;
|
|
984
995
|
if (level.rPr?.allCaps) listRendering.markerAllCaps = true;
|
|
985
996
|
if (level.lvlJc) listRendering.markerAlignment = level.lvlJc;
|
|
986
997
|
if (level.suffix) listRendering.markerSuffix = level.suffix;
|
package/dist/docx/parser.d.ts
CHANGED
package/dist/docx/parser.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
2
|
-
import { applyThemeFontLang, parseTheme } from "./themeParser.js";
|
|
3
|
-
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
4
|
-
import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
|
|
5
|
-
import { parseNumbering } from "./numberingParser.js";
|
|
6
|
-
import { DocxEncryptionError } from "./encryption/errors.js";
|
|
7
|
-
import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
|
|
8
|
-
import { parseComments } from "./commentParser.js";
|
|
9
|
-
import { parseFooter, parseHeader } from "./headerFooterParser.js";
|
|
10
1
|
import { toArrayBuffer } from "../utils/docxInput.js";
|
|
11
2
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
12
3
|
import { convertTiffToPngDataUrl, isTiffMimeType } from "../utils/tiffConverter.js";
|
|
4
|
+
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
5
|
+
import { applyThemeFontLang, parseTheme } from "./themeParser.js";
|
|
6
|
+
import { parseComments } from "./commentParser.js";
|
|
13
7
|
import { normalizeCommentReferences } from "./commentReferenceNormalization.js";
|
|
14
8
|
import { detectDocxConformanceClass } from "./conformance.js";
|
|
9
|
+
import { parseCoreProperties } from "./corePropertiesParser.js";
|
|
10
|
+
import { parseNumbering } from "./numberingParser.js";
|
|
15
11
|
import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
|
|
12
|
+
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
13
|
+
import { parseFooter, parseHeader } from "./headerFooterParser.js";
|
|
16
14
|
import { normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
|
|
15
|
+
import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
|
|
17
16
|
import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
|
|
17
|
+
import { parseFontTable } from "./fontTableParser.js";
|
|
18
18
|
import { normalizeNumberingReferences } from "./numberingReferenceNormalization.js";
|
|
19
19
|
import { parseSettings } from "./settingsParser.js";
|
|
20
20
|
import { parseStylesPackage } from "./styleParser.js";
|
|
21
21
|
import { normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
|
|
22
|
+
import { DocxEncryptionError } from "./encryption/errors.js";
|
|
23
|
+
import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
|
|
22
24
|
import { TaggedError } from "better-result";
|
|
23
25
|
//#region src/docx/parser.ts
|
|
24
26
|
/**
|
|
@@ -84,6 +86,7 @@ async function parseDocx(input, options = {}) {
|
|
|
84
86
|
onProgress("Parsed styles", 30);
|
|
85
87
|
onProgress("Parsing numbering...", 30);
|
|
86
88
|
const numbering = timeStage("numbering", () => parseNumbering(raw.numberingXml));
|
|
89
|
+
const fontTable = timeStage("fontTable", () => parseFontTable(raw.fontTableXml));
|
|
87
90
|
onProgress("Parsed numbering", 35);
|
|
88
91
|
onProgress("Processing media files...", 35);
|
|
89
92
|
const media = await timeStageAsync("media", () => buildMediaMap(raw, rels));
|
|
@@ -166,6 +169,7 @@ async function parseDocx(input, options = {}) {
|
|
|
166
169
|
onProgress("Loaded fonts", 95);
|
|
167
170
|
} else onProgress("Skipping font loading", 95);
|
|
168
171
|
onProgress("Assembling document...", 95);
|
|
172
|
+
const properties = timeStage("coreProperties", () => parseCoreProperties(raw.corePropsXml));
|
|
169
173
|
const document = {
|
|
170
174
|
package: {
|
|
171
175
|
conformanceClass: detectDocxConformanceClass(raw.documentXml),
|
|
@@ -174,12 +178,14 @@ async function parseDocx(input, options = {}) {
|
|
|
174
178
|
...styleDefinitions !== void 0 ? { styles: styleDefinitions } : {},
|
|
175
179
|
theme,
|
|
176
180
|
numbering: numbering.definitions,
|
|
181
|
+
...fontTable ? { fontTable } : {},
|
|
177
182
|
...headers !== void 0 ? { headers } : {},
|
|
178
183
|
...footers !== void 0 ? { footers } : {},
|
|
179
184
|
...footnotes !== void 0 ? { footnotes } : {},
|
|
180
185
|
...endnotes !== void 0 ? { endnotes } : {},
|
|
181
186
|
relationships: rels,
|
|
182
|
-
media
|
|
187
|
+
media,
|
|
188
|
+
...properties !== void 0 ? { properties } : {}
|
|
183
189
|
},
|
|
184
190
|
originalBuffer: raw.originalBuffer,
|
|
185
191
|
...templateVariables !== void 0 ? { templateVariables } : {},
|
package/dist/docx/rezip.d.ts
CHANGED
|
@@ -124,10 +124,11 @@ declare function hasUnmaterializedHeaderFooter(doc: document_d_exports.Document)
|
|
|
124
124
|
*/
|
|
125
125
|
declare function hasModelDrivenPictureWatermark(doc: document_d_exports.Document): boolean;
|
|
126
126
|
declare function collectHeaderFooterUpdates(doc: document_d_exports.Document): Map<string, string>;
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
/** Update existing core-property values without synthesizing absent metadata. */
|
|
128
|
+
declare function updateCoreProperties(corePropsXml: string, {
|
|
129
|
+
updateModifiedDate,
|
|
130
|
+
modifiedBy
|
|
131
|
+
}: {
|
|
131
132
|
updateModifiedDate?: boolean;
|
|
132
133
|
modifiedBy?: string;
|
|
133
134
|
}): string;
|
package/dist/docx/rezip.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
2
1
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
2
|
+
import { parseNumbering } from "./numberingParser.js";
|
|
3
3
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
4
4
|
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
5
|
-
import {
|
|
5
|
+
import { isPreservableDocxEntry } from "./unzip.js";
|
|
6
|
+
import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
6
7
|
import { buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, extractParagraphXml } from "./selectiveXmlPatch.js";
|
|
7
8
|
import { escapeXml } from "./serializer/xmlUtils.js";
|
|
8
9
|
import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
@@ -10,7 +11,10 @@ import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
|
10
11
|
import { serializeHeaderFooter } from "./serializer/headerFooterSerializer.js";
|
|
11
12
|
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
12
13
|
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
13
|
-
import {
|
|
14
|
+
import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
|
|
15
|
+
import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
|
|
16
|
+
import { serializeStylesXml } from "./serializer/stylesSerializer.js";
|
|
17
|
+
import { serializeThemeXml } from "./serializer/themeSerializer.js";
|
|
14
18
|
import { panic } from "better-result";
|
|
15
19
|
import JSZip from "jszip";
|
|
16
20
|
//#region src/docx/rezip.ts
|
|
@@ -1018,18 +1022,16 @@ function findNotePartEntry(zip, conventionalLowerPath) {
|
|
|
1018
1022
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === conventionalLowerPath) return file;
|
|
1019
1023
|
return null;
|
|
1020
1024
|
}
|
|
1021
|
-
/**
|
|
1022
|
-
|
|
1023
|
-
*/
|
|
1024
|
-
function updateCoreProperties(corePropsXml, options) {
|
|
1025
|
+
/** Update existing core-property values without synthesizing absent metadata. */
|
|
1026
|
+
function updateCoreProperties(corePropsXml, { updateModifiedDate, modifiedBy }) {
|
|
1025
1027
|
let result = corePropsXml;
|
|
1026
|
-
if (
|
|
1028
|
+
if (updateModifiedDate) {
|
|
1027
1029
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1028
1030
|
if (result.includes("<dcterms:modified")) result = result.replace(/<dcterms:modified[^<>]*>[^<]*<\/dcterms:modified>/u, `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>`);
|
|
1029
|
-
else result = result.replace("</cp:coreProperties>", `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified></cp:coreProperties>`);
|
|
1030
1031
|
}
|
|
1031
|
-
if (
|
|
1032
|
-
|
|
1032
|
+
if (modifiedBy) {
|
|
1033
|
+
if (result.includes("<cp:lastModifiedBy")) result = result.replace(/<cp:lastModifiedBy>[^<]*<\/cp:lastModifiedBy>/u, `<cp:lastModifiedBy>${escapeXml(modifiedBy)}</cp:lastModifiedBy>`);
|
|
1034
|
+
}
|
|
1033
1035
|
return result;
|
|
1034
1036
|
}
|
|
1035
1037
|
/**
|
|
@@ -1169,7 +1171,7 @@ function createEmptyDocx() {
|
|
|
1169
1171
|
zip.file("docProps/app.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1170
1172
|
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
|
|
1171
1173
|
<Application>EigenPal DOCX Editor</Application>
|
|
1172
|
-
<AppVersion>1.
|
|
1174
|
+
<AppVersion>1.0000</AppVersion>
|
|
1173
1175
|
</Properties>`);
|
|
1174
1176
|
return zip.generateAsync({
|
|
1175
1177
|
type: "arraybuffer",
|
|
@@ -1184,11 +1186,72 @@ function createEmptyDocx() {
|
|
|
1184
1186
|
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
1185
1187
|
*/
|
|
1186
1188
|
async function createDocx(doc) {
|
|
1187
|
-
const emptyBuffer = await
|
|
1189
|
+
const emptyBuffer = await createDocumentSeedDocx(doc);
|
|
1188
1190
|
return repackDocx({
|
|
1189
1191
|
...doc,
|
|
1190
1192
|
originalBuffer: emptyBuffer
|
|
1191
1193
|
});
|
|
1192
1194
|
}
|
|
1195
|
+
const createDocumentSeedDocx = async (doc) => {
|
|
1196
|
+
const buffer = await createEmptyDocx();
|
|
1197
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
1198
|
+
const relationships = ["<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>"];
|
|
1199
|
+
const overrides = [];
|
|
1200
|
+
let nextRelationshipId = 2;
|
|
1201
|
+
if (doc.package.styles) {
|
|
1202
|
+
assertStyleNumberingReferences(doc);
|
|
1203
|
+
zip.file("word/styles.xml", serializeStylesXml(doc.package.styles));
|
|
1204
|
+
}
|
|
1205
|
+
const numbering = doc.package.numbering;
|
|
1206
|
+
if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
|
|
1207
|
+
zip.file("word/numbering.xml", serializeNumberingXml(numbering));
|
|
1208
|
+
relationships.push(relationshipXml(nextRelationshipId, "numbering", "numbering.xml"));
|
|
1209
|
+
overrides.push(overrideXml("/word/numbering.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"));
|
|
1210
|
+
nextRelationshipId += 1;
|
|
1211
|
+
}
|
|
1212
|
+
if (doc.package.theme) {
|
|
1213
|
+
zip.file("word/theme/theme1.xml", serializeThemeXml(doc.package.theme));
|
|
1214
|
+
relationships.push(relationshipXml(nextRelationshipId, "theme", "theme/theme1.xml"));
|
|
1215
|
+
overrides.push(overrideXml("/word/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"));
|
|
1216
|
+
nextRelationshipId += 1;
|
|
1217
|
+
}
|
|
1218
|
+
if (doc.package.fontTable && doc.package.fontTable.fonts.length > 0) {
|
|
1219
|
+
zip.file("word/fontTable.xml", serializeFontTableXml(doc.package.fontTable));
|
|
1220
|
+
relationships.push(relationshipXml(nextRelationshipId, "fontTable", "fontTable.xml"));
|
|
1221
|
+
overrides.push(overrideXml("/word/fontTable.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"));
|
|
1222
|
+
nextRelationshipId += 1;
|
|
1223
|
+
}
|
|
1224
|
+
if (doc.package.settings) {
|
|
1225
|
+
zip.file("word/settings.xml", serializeSettingsXml(doc.package.settings));
|
|
1226
|
+
relationships.push(relationshipXml(nextRelationshipId, "settings", "settings.xml"));
|
|
1227
|
+
overrides.push(overrideXml("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"));
|
|
1228
|
+
}
|
|
1229
|
+
zip.file("word/_rels/document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${relationships.join("")}</Relationships>`);
|
|
1230
|
+
if (overrides.length > 0) {
|
|
1231
|
+
const contentTypesFile = zip.file("[Content_Types].xml");
|
|
1232
|
+
if (!contentTypesFile) panic("Fresh DOCX seed is missing [Content_Types].xml");
|
|
1233
|
+
const contentTypes = await contentTypesFile.async("string");
|
|
1234
|
+
zip.file("[Content_Types].xml", contentTypes.replace("</Types>", `${overrides.join("")}\n</Types>`));
|
|
1235
|
+
}
|
|
1236
|
+
return zip.generateAsync({
|
|
1237
|
+
type: "arraybuffer",
|
|
1238
|
+
compression: "DEFLATE",
|
|
1239
|
+
compressionOptions: { level: 6 }
|
|
1240
|
+
});
|
|
1241
|
+
};
|
|
1242
|
+
const relationshipXml = (id, type, target) => `<Relationship Id="rId${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>`;
|
|
1243
|
+
const overrideXml = (partName, contentType) => `<Override PartName="${partName}" ContentType="${contentType}"/>`;
|
|
1244
|
+
const assertStyleNumberingReferences = (doc) => {
|
|
1245
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
1246
|
+
for (const style of doc.package.styles?.styles ?? []) {
|
|
1247
|
+
const numId = style.pPr?.numPr?.numId;
|
|
1248
|
+
if (numId !== void 0) referenced.add(numId);
|
|
1249
|
+
}
|
|
1250
|
+
if (referenced.size === 0) return;
|
|
1251
|
+
const available = new Set(doc.package.numbering?.nums.map((numbering) => numbering.numId) ?? []);
|
|
1252
|
+
for (const numId of referenced) if (!available.has(numId)) panic(`Style references missing numbering definition ${numId}`);
|
|
1253
|
+
const availableAbstract = new Set(doc.package.numbering?.abstractNums.map((numbering) => numbering.abstractNumId) ?? []);
|
|
1254
|
+
for (const numbering of doc.package.numbering?.nums ?? []) if (!availableAbstract.has(numbering.abstractNumId)) panic(`Numbering definition ${numbering.numId} references missing abstract numbering`);
|
|
1255
|
+
};
|
|
1193
1256
|
//#endregion
|
|
1194
1257
|
export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, isDocxBuffer, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx };
|
|
@@ -38,8 +38,12 @@ function formattingEquals(a, b) {
|
|
|
38
38
|
if (!colorEquals(a.color, b.color)) return false;
|
|
39
39
|
if (!shadingEquals(a.shading, b.shading)) return false;
|
|
40
40
|
if (!fontFamilyEquals(a.fontFamily, b.fontFamily)) return false;
|
|
41
|
+
if (!languageEquals(a.language, b.language)) return false;
|
|
41
42
|
return true;
|
|
42
43
|
}
|
|
44
|
+
function languageEquals(a, b) {
|
|
45
|
+
return a?.val === b?.val && a?.eastAsia === b?.eastAsia && a?.bidi === b?.bidi;
|
|
46
|
+
}
|
|
43
47
|
/**
|
|
44
48
|
* Compare underline settings
|
|
45
49
|
*/
|
package/dist/docx/runParser.js
CHANGED
|
@@ -89,6 +89,9 @@ function collectFirstRunPropertyChildren(rPr) {
|
|
|
89
89
|
case "kern":
|
|
90
90
|
children.kern ??= child;
|
|
91
91
|
break;
|
|
92
|
+
case "lang":
|
|
93
|
+
children.lang ??= child;
|
|
94
|
+
break;
|
|
92
95
|
case "outline":
|
|
93
96
|
children.outline ??= child;
|
|
94
97
|
break;
|
|
@@ -262,6 +265,17 @@ function parseRunProperties(rPr, theme, _styles) {
|
|
|
262
265
|
}
|
|
263
266
|
formatting.fontFamily = fontFamily;
|
|
264
267
|
}
|
|
268
|
+
const lang = propertyChildren.lang;
|
|
269
|
+
if (lang) {
|
|
270
|
+
const val = getAttribute(lang, "w", "val") || void 0;
|
|
271
|
+
const eastAsia = getAttribute(lang, "w", "eastAsia") || void 0;
|
|
272
|
+
const bidi = getAttribute(lang, "w", "bidi") || void 0;
|
|
273
|
+
if (val || eastAsia || bidi) formatting.language = {
|
|
274
|
+
...val ? { val } : {},
|
|
275
|
+
...eastAsia ? { eastAsia } : {},
|
|
276
|
+
...bidi ? { bidi } : {}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
265
279
|
const spacing = propertyChildren.spacing;
|
|
266
280
|
if (spacing) {
|
|
267
281
|
const val = parseNumericAttribute(spacing, "w", "val");
|
|
@@ -531,7 +545,11 @@ function parseRunContents(runElement, rels, media, rootXmlns = {}) {
|
|
|
531
545
|
if (vmlDrawing) contents.push(vmlDrawing);
|
|
532
546
|
break;
|
|
533
547
|
}
|
|
534
|
-
case "object":
|
|
548
|
+
case "object": {
|
|
549
|
+
const objectPreview = parseVmlImageContent(child, rels, media, rootXmlns);
|
|
550
|
+
if (objectPreview) contents.push(objectPreview);
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
535
553
|
case "rPr": break;
|
|
536
554
|
case "lastRenderedPageBreak": break;
|
|
537
555
|
case "cr":
|