@cj-tech-master/excelts 9.5.0 → 9.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/modules/pdf/excel-bridge.js +27 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +74 -9
- package/dist/browser/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/browser/modules/pdf/render/style-converter.js +98 -1
- package/dist/browser/modules/pdf/types.d.ts +1 -0
- package/dist/browser/modules/word/color-utils.d.ts +18 -0
- package/dist/browser/modules/word/color-utils.js +94 -0
- package/dist/browser/modules/word/content-types.d.ts +15 -15
- package/dist/browser/modules/word/content-types.js +39 -43
- package/dist/browser/modules/word/crypto.d.ts +17 -0
- package/dist/browser/modules/word/crypto.js +18 -0
- package/dist/browser/modules/word/document-io.d.ts +58 -0
- package/dist/browser/modules/word/document-io.js +239 -0
- package/dist/browser/modules/word/document.d.ts +64 -135
- package/dist/browser/modules/word/document.js +207 -469
- package/dist/browser/modules/word/docx-packager.js +90 -90
- package/dist/browser/modules/word/html-renderer.js +1 -1
- package/dist/browser/modules/word/html.d.ts +13 -0
- package/dist/browser/modules/word/html.js +12 -0
- package/dist/browser/modules/word/index.base.d.ts +6 -9
- package/dist/browser/modules/word/index.base.js +7 -10
- package/dist/browser/modules/word/namespaces.d.ts +159 -0
- package/dist/browser/modules/word/namespaces.js +189 -0
- package/dist/browser/modules/word/relationships.d.ts +15 -16
- package/dist/browser/modules/word/relationships.js +37 -45
- package/dist/cjs/modules/pdf/excel-bridge.js +27 -1
- package/dist/cjs/modules/pdf/render/layout-engine.js +74 -9
- package/dist/cjs/modules/pdf/render/style-converter.js +98 -1
- package/dist/cjs/modules/word/color-utils.js +97 -0
- package/dist/cjs/modules/word/content-types.js +44 -45
- package/dist/cjs/modules/word/crypto.js +34 -0
- package/dist/cjs/modules/word/document-io.js +244 -0
- package/dist/cjs/modules/word/document.js +209 -473
- package/dist/cjs/modules/word/docx-packager.js +88 -88
- package/dist/cjs/modules/word/html-renderer.js +2 -2
- package/dist/cjs/modules/word/html.js +16 -0
- package/dist/cjs/modules/word/index.base.js +17 -27
- package/dist/cjs/modules/word/namespaces.js +192 -0
- package/dist/cjs/modules/word/relationships.js +42 -47
- package/dist/esm/modules/pdf/excel-bridge.js +27 -1
- package/dist/esm/modules/pdf/render/layout-engine.js +74 -9
- package/dist/esm/modules/pdf/render/style-converter.js +98 -1
- package/dist/esm/modules/word/color-utils.js +94 -0
- package/dist/esm/modules/word/content-types.js +39 -43
- package/dist/esm/modules/word/crypto.js +18 -0
- package/dist/esm/modules/word/document-io.js +239 -0
- package/dist/esm/modules/word/document.js +207 -469
- package/dist/esm/modules/word/docx-packager.js +90 -90
- package/dist/esm/modules/word/html-renderer.js +1 -1
- package/dist/esm/modules/word/html.js +12 -0
- package/dist/esm/modules/word/index.base.js +7 -10
- package/dist/esm/modules/word/namespaces.js +189 -0
- package/dist/esm/modules/word/relationships.js +37 -45
- package/dist/iife/excelts.iife.js +153 -11
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +4 -4
- package/dist/types/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/types/modules/pdf/types.d.ts +1 -0
- package/dist/types/modules/word/color-utils.d.ts +18 -0
- package/dist/types/modules/word/content-types.d.ts +15 -15
- package/dist/types/modules/word/crypto.d.ts +17 -0
- package/dist/types/modules/word/document-io.d.ts +58 -0
- package/dist/types/modules/word/document.d.ts +64 -135
- package/dist/types/modules/word/html.d.ts +13 -0
- package/dist/types/modules/word/index.base.d.ts +6 -9
- package/dist/types/modules/word/namespaces.d.ts +159 -0
- package/dist/types/modules/word/relationships.d.ts +15 -16
- package/package.json +1 -1
|
@@ -62,7 +62,7 @@ function argbToPdfColor(argb) {
|
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
64
|
* Convert a color data object to PDF color.
|
|
65
|
-
* Handles
|
|
65
|
+
* Handles ARGB, theme-based, and indexed colors.
|
|
66
66
|
*/
|
|
67
67
|
function excelColorToPdf(color) {
|
|
68
68
|
if (!color) {
|
|
@@ -84,6 +84,10 @@ function excelColorToPdf(color) {
|
|
|
84
84
|
}
|
|
85
85
|
return base;
|
|
86
86
|
}
|
|
87
|
+
// Indexed colors (legacy Excel color palette)
|
|
88
|
+
if (color.indexed !== undefined) {
|
|
89
|
+
return indexedColorToPdf(color.indexed);
|
|
90
|
+
}
|
|
87
91
|
return null;
|
|
88
92
|
}
|
|
89
93
|
/**
|
|
@@ -109,6 +113,99 @@ function themeColorToPdf(themeIndex) {
|
|
|
109
113
|
}
|
|
110
114
|
return null;
|
|
111
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Standard Excel indexed color palette (56 colors + system colors).
|
|
118
|
+
* Index 0–7: legacy base colors
|
|
119
|
+
* Index 8–63: standard palette (indices 8–63)
|
|
120
|
+
* Index 64: system foreground (black)
|
|
121
|
+
* Index 65: system background (white)
|
|
122
|
+
*
|
|
123
|
+
* @see ECMA-376 §18.8.27 — indexedColors
|
|
124
|
+
*/
|
|
125
|
+
const INDEXED_COLORS = [
|
|
126
|
+
// 0–7: legacy base colors (same as 8–15 but less commonly used directly)
|
|
127
|
+
"000000", // 0: Black
|
|
128
|
+
"FFFFFF", // 1: White
|
|
129
|
+
"FF0000", // 2: Red
|
|
130
|
+
"00FF00", // 3: Green
|
|
131
|
+
"0000FF", // 4: Blue
|
|
132
|
+
"FFFF00", // 5: Yellow
|
|
133
|
+
"FF00FF", // 6: Magenta
|
|
134
|
+
"00FFFF", // 7: Cyan
|
|
135
|
+
// 8–63: standard palette
|
|
136
|
+
"000000", // 8: Black
|
|
137
|
+
"FFFFFF", // 9: White
|
|
138
|
+
"FF0000", // 10: Red
|
|
139
|
+
"00FF00", // 11: Green
|
|
140
|
+
"0000FF", // 12: Blue
|
|
141
|
+
"FFFF00", // 13: Yellow
|
|
142
|
+
"FF00FF", // 14: Magenta
|
|
143
|
+
"00FFFF", // 15: Cyan
|
|
144
|
+
"800000", // 16: Dark Red
|
|
145
|
+
"008000", // 17: Dark Green
|
|
146
|
+
"000080", // 18: Dark Blue (Navy)
|
|
147
|
+
"808000", // 19: Dark Yellow (Olive)
|
|
148
|
+
"800080", // 20: Purple
|
|
149
|
+
"008080", // 21: Teal
|
|
150
|
+
"C0C0C0", // 22: Silver
|
|
151
|
+
"808080", // 23: Gray
|
|
152
|
+
"9999FF", // 24: Periwinkle
|
|
153
|
+
"993366", // 25: Plum
|
|
154
|
+
"FFFFCC", // 26: Ivory
|
|
155
|
+
"CCFFFF", // 27: Light Cyan
|
|
156
|
+
"660066", // 28: Dark Purple
|
|
157
|
+
"FF8080", // 29: Coral
|
|
158
|
+
"0066CC", // 30: Ocean Blue
|
|
159
|
+
"CCCCFF", // 31: Ice Blue
|
|
160
|
+
"000080", // 32: Dark Blue
|
|
161
|
+
"FF00FF", // 33: Pink
|
|
162
|
+
"FFFF00", // 34: Yellow
|
|
163
|
+
"00FFFF", // 35: Cyan
|
|
164
|
+
"800080", // 36: Purple
|
|
165
|
+
"800000", // 37: Dark Red
|
|
166
|
+
"008080", // 38: Teal
|
|
167
|
+
"0000FF", // 39: Blue
|
|
168
|
+
"00CCFF", // 40: Sky Blue
|
|
169
|
+
"CCFFFF", // 41: Light Turquoise
|
|
170
|
+
"CCFFCC", // 42: Light Green
|
|
171
|
+
"FFFF99", // 43: Light Yellow
|
|
172
|
+
"99CCFF", // 44: Pale Blue
|
|
173
|
+
"FF99CC", // 45: Rose
|
|
174
|
+
"CC99FF", // 46: Lavender
|
|
175
|
+
"FFCC99", // 47: Tan
|
|
176
|
+
"3366FF", // 48: Light Blue
|
|
177
|
+
"33CCCC", // 49: Aqua
|
|
178
|
+
"99CC00", // 50: Lime
|
|
179
|
+
"FFCC00", // 51: Gold
|
|
180
|
+
"FF9900", // 52: Light Orange
|
|
181
|
+
"FF6600", // 53: Orange
|
|
182
|
+
"666699", // 54: Blue Gray
|
|
183
|
+
"969696", // 55: Gray 40%
|
|
184
|
+
"003366", // 56: Dark Teal
|
|
185
|
+
"339966", // 57: Sea Green
|
|
186
|
+
"003300", // 58: Very Dark Green
|
|
187
|
+
"333300", // 59: Dark Olive
|
|
188
|
+
"993300", // 60: Brown
|
|
189
|
+
"993366", // 61: Plum
|
|
190
|
+
"333399", // 62: Indigo
|
|
191
|
+
"333333" // 63: Gray 80%
|
|
192
|
+
];
|
|
193
|
+
/**
|
|
194
|
+
* Convert an indexed color to PDF color.
|
|
195
|
+
* Index 64 = system foreground (black), 65 = system background (white).
|
|
196
|
+
*/
|
|
197
|
+
function indexedColorToPdf(index) {
|
|
198
|
+
if (index === 64) {
|
|
199
|
+
return { r: 0, g: 0, b: 0 }; // System foreground (black)
|
|
200
|
+
}
|
|
201
|
+
if (index === 65) {
|
|
202
|
+
return { r: 1, g: 1, b: 1 }; // System background (white)
|
|
203
|
+
}
|
|
204
|
+
if (index >= 0 && index < INDEXED_COLORS.length) {
|
|
205
|
+
return argbToPdfColor(INDEXED_COLORS[index]) ?? null;
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
112
209
|
/**
|
|
113
210
|
* Apply a tint value to a color.
|
|
114
211
|
* Tint range: -1.0 (fully dark) to +1.0 (fully light).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DOCX Module - Theme Color Utilities
|
|
4
|
+
*
|
|
5
|
+
* Resolves OOXML theme colors with tint/shade transformations.
|
|
6
|
+
* Extracted to a standalone file so that html-renderer and document.ts
|
|
7
|
+
* can both import it without creating circular heavy dependencies.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.resolveThemeColor = resolveThemeColor;
|
|
11
|
+
/**
|
|
12
|
+
* Map OOXML theme color attribute names to theme color scheme keys.
|
|
13
|
+
* Word uses different names in run/paragraph properties vs the theme XML.
|
|
14
|
+
*/
|
|
15
|
+
const THEME_COLOR_MAP = {
|
|
16
|
+
dark1: "dk1",
|
|
17
|
+
light1: "lt1",
|
|
18
|
+
dark2: "dk2",
|
|
19
|
+
light2: "lt2",
|
|
20
|
+
accent1: "accent1",
|
|
21
|
+
accent2: "accent2",
|
|
22
|
+
accent3: "accent3",
|
|
23
|
+
accent4: "accent4",
|
|
24
|
+
accent5: "accent5",
|
|
25
|
+
accent6: "accent6",
|
|
26
|
+
hyperlink: "hlink",
|
|
27
|
+
followedHyperlink: "folHlink",
|
|
28
|
+
// Direct names also work
|
|
29
|
+
dk1: "dk1",
|
|
30
|
+
lt1: "lt1",
|
|
31
|
+
dk2: "dk2",
|
|
32
|
+
lt2: "lt2",
|
|
33
|
+
hlink: "hlink",
|
|
34
|
+
folHlink: "folHlink"
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a ColorSpec to an actual hex RGB color using the document theme.
|
|
38
|
+
*
|
|
39
|
+
* Applies theme color lookup + tint/shade transformations per OOXML spec.
|
|
40
|
+
*
|
|
41
|
+
* @param color - The color value (HexColor string or ColorSpec).
|
|
42
|
+
* @param theme - The document theme (from `doc.theme`).
|
|
43
|
+
* @returns Resolved hex color string (6 chars, no #), or undefined if unresolvable.
|
|
44
|
+
*/
|
|
45
|
+
function resolveThemeColor(color, theme) {
|
|
46
|
+
if (color === undefined) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if (typeof color === "string") {
|
|
50
|
+
return color;
|
|
51
|
+
}
|
|
52
|
+
// ColorSpec with val — use directly
|
|
53
|
+
if (color.val && color.val !== "auto") {
|
|
54
|
+
return color.val;
|
|
55
|
+
}
|
|
56
|
+
// Resolve via theme
|
|
57
|
+
if (!color.themeColor || !theme) {
|
|
58
|
+
return color.val;
|
|
59
|
+
}
|
|
60
|
+
const key = THEME_COLOR_MAP[color.themeColor] ?? color.themeColor;
|
|
61
|
+
const base = theme.colorScheme.colors[key];
|
|
62
|
+
if (!base) {
|
|
63
|
+
return color.val;
|
|
64
|
+
}
|
|
65
|
+
// Apply tint or shade
|
|
66
|
+
if (color.themeTint) {
|
|
67
|
+
return applyTint(base, parseInt(color.themeTint, 16) / 255);
|
|
68
|
+
}
|
|
69
|
+
if (color.themeShade) {
|
|
70
|
+
return applyShade(base, parseInt(color.themeShade, 16) / 255);
|
|
71
|
+
}
|
|
72
|
+
return base;
|
|
73
|
+
}
|
|
74
|
+
/** Apply tint to a hex color. tint=1 → white, tint=0 → original. */
|
|
75
|
+
function applyTint(hex, tint) {
|
|
76
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
77
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
78
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
79
|
+
const nr = Math.round(r + (255 - r) * tint);
|
|
80
|
+
const ng = Math.round(g + (255 - g) * tint);
|
|
81
|
+
const nb = Math.round(b + (255 - b) * tint);
|
|
82
|
+
return toHex2(nr) + toHex2(ng) + toHex2(nb);
|
|
83
|
+
}
|
|
84
|
+
/** Apply shade to a hex color. shade=1 → original, shade=0 → black. */
|
|
85
|
+
function applyShade(hex, shade) {
|
|
86
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
87
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
88
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
89
|
+
const nr = Math.round(r * shade);
|
|
90
|
+
const ng = Math.round(g * shade);
|
|
91
|
+
const nb = Math.round(b * shade);
|
|
92
|
+
return toHex2(nr) + toHex2(ng) + toHex2(nb);
|
|
93
|
+
}
|
|
94
|
+
function toHex2(n) {
|
|
95
|
+
const h = Math.max(0, Math.min(255, n)).toString(16);
|
|
96
|
+
return h.length < 2 ? "0" + h : h;
|
|
97
|
+
}
|
|
@@ -3,55 +3,54 @@
|
|
|
3
3
|
* DOCX Module - Content Types Generator
|
|
4
4
|
*
|
|
5
5
|
* Generates [Content_Types].xml for the DOCX package.
|
|
6
|
+
* Uses a plain data record + free functions for tree-shakeability.
|
|
6
7
|
*/
|
|
7
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
+
exports.createContentTypes = createContentTypes;
|
|
10
|
+
exports.addContentTypeDefault = addContentTypeDefault;
|
|
11
|
+
exports.addContentTypeOverride = addContentTypeOverride;
|
|
12
|
+
exports.addImageContentTypeDefaults = addImageContentTypeDefaults;
|
|
13
|
+
exports.renderContentTypes = renderContentTypes;
|
|
9
14
|
const constants_1 = require("./constants");
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
for (const ext of extensions) {
|
|
35
|
-
const ct = constants_1.IMAGE_CONTENT_TYPES[ext.toLowerCase()];
|
|
36
|
-
if (ct) {
|
|
37
|
-
this._defaults.set(ext.toLowerCase(), ct);
|
|
38
|
-
}
|
|
15
|
+
/** Create a new ContentTypesState with standard defaults (rels, xml). */
|
|
16
|
+
function createContentTypes() {
|
|
17
|
+
const defaults = new Map();
|
|
18
|
+
defaults.set("rels", constants_1.ContentType.Relationships);
|
|
19
|
+
defaults.set("xml", constants_1.ContentType.Xml);
|
|
20
|
+
return { defaults, overrides: [] };
|
|
21
|
+
}
|
|
22
|
+
/** Add a default content type for a file extension. */
|
|
23
|
+
function addContentTypeDefault(state, extension, contentType) {
|
|
24
|
+
state.defaults.set(extension, contentType);
|
|
25
|
+
}
|
|
26
|
+
/** Add an override content type for a specific part. */
|
|
27
|
+
function addContentTypeOverride(state, partName, contentType) {
|
|
28
|
+
state.overrides.push({
|
|
29
|
+
partName: partName.startsWith("/") ? partName : `/${partName}`,
|
|
30
|
+
contentType
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Add image extension defaults from a set of used extensions. */
|
|
34
|
+
function addImageContentTypeDefaults(state, extensions) {
|
|
35
|
+
for (const ext of extensions) {
|
|
36
|
+
const ct = constants_1.IMAGE_CONTENT_TYPES[ext.toLowerCase()];
|
|
37
|
+
if (ct) {
|
|
38
|
+
state.defaults.set(ext.toLowerCase(), ct);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
xml.closeNode();
|
|
41
|
+
}
|
|
42
|
+
/** Render the [Content_Types].xml to a sink. */
|
|
43
|
+
function renderContentTypes(state, xml) {
|
|
44
|
+
xml.openXml(constants_1.STD_DOC_ATTRIBUTES);
|
|
45
|
+
xml.openNode("Types", { xmlns: constants_1.NS_CONTENT_TYPES });
|
|
46
|
+
// Defaults sorted by extension
|
|
47
|
+
const sortedDefaults = [...state.defaults.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
48
|
+
for (const [ext, ct] of sortedDefaults) {
|
|
49
|
+
xml.leafNode("Default", { Extension: ext, ContentType: ct });
|
|
50
|
+
}
|
|
51
|
+
// Overrides in order
|
|
52
|
+
for (const override of state.overrides) {
|
|
53
|
+
xml.leafNode("Override", { PartName: override.partName, ContentType: override.contentType });
|
|
55
54
|
}
|
|
55
|
+
xml.closeNode();
|
|
56
56
|
}
|
|
57
|
-
exports.ContentTypesManager = ContentTypesManager;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DOCX Module - Encryption & Digital Signatures (Subpath Export)
|
|
4
|
+
*
|
|
5
|
+
* Import separately to avoid pulling crypto code into the bundle
|
|
6
|
+
* when only core document building is needed.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { isEncryptedDocx, decryptPackage } from "excelts/word/crypto";
|
|
11
|
+
* import { extractSignatures } from "excelts/word/crypto";
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.generateFontKey = exports.obfuscateFont = exports.deobfuscateFont = exports.isWellFormedSignature = exports.extractSignatures = exports.parseSignatureXml = exports.hasDigitalSignatures = exports.AGILE_BLOCK_KEYS = exports.deriveEncryptionKey = exports.parseEncryptionInfoXml = exports.decryptPackage = exports.verifyPassword = exports.isEncryptedDocx = void 0;
|
|
16
|
+
// Encryption utilities
|
|
17
|
+
var encryption_1 = require("./encryption");
|
|
18
|
+
Object.defineProperty(exports, "isEncryptedDocx", { enumerable: true, get: function () { return encryption_1.isEncryptedDocx; } });
|
|
19
|
+
Object.defineProperty(exports, "verifyPassword", { enumerable: true, get: function () { return encryption_1.verifyPassword; } });
|
|
20
|
+
Object.defineProperty(exports, "decryptPackage", { enumerable: true, get: function () { return encryption_1.decryptPackage; } });
|
|
21
|
+
Object.defineProperty(exports, "parseEncryptionInfoXml", { enumerable: true, get: function () { return encryption_1.parseEncryptionInfoXml; } });
|
|
22
|
+
Object.defineProperty(exports, "deriveEncryptionKey", { enumerable: true, get: function () { return encryption_1.deriveEncryptionKey; } });
|
|
23
|
+
Object.defineProperty(exports, "AGILE_BLOCK_KEYS", { enumerable: true, get: function () { return encryption_1.AGILE_BLOCK_KEYS; } });
|
|
24
|
+
// Digital signature utilities
|
|
25
|
+
var digital_signatures_1 = require("./digital-signatures");
|
|
26
|
+
Object.defineProperty(exports, "hasDigitalSignatures", { enumerable: true, get: function () { return digital_signatures_1.hasDigitalSignatures; } });
|
|
27
|
+
Object.defineProperty(exports, "parseSignatureXml", { enumerable: true, get: function () { return digital_signatures_1.parseSignatureXml; } });
|
|
28
|
+
Object.defineProperty(exports, "extractSignatures", { enumerable: true, get: function () { return digital_signatures_1.extractSignatures; } });
|
|
29
|
+
Object.defineProperty(exports, "isWellFormedSignature", { enumerable: true, get: function () { return digital_signatures_1.isWellFormedSignature; } });
|
|
30
|
+
// Font obfuscation utilities
|
|
31
|
+
var font_obfuscation_1 = require("./font-obfuscation");
|
|
32
|
+
Object.defineProperty(exports, "deobfuscateFont", { enumerable: true, get: function () { return font_obfuscation_1.deobfuscateFont; } });
|
|
33
|
+
Object.defineProperty(exports, "obfuscateFont", { enumerable: true, get: function () { return font_obfuscation_1.obfuscateFont; } });
|
|
34
|
+
Object.defineProperty(exports, "generateFontKey", { enumerable: true, get: function () { return font_obfuscation_1.generateFontKey; } });
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DOCX Module - Document IO
|
|
4
|
+
*
|
|
5
|
+
* IO operations that depend on docx-packager and docx-reader.
|
|
6
|
+
* Separated from document.ts so that builder helpers can be imported
|
|
7
|
+
* without pulling in archive/xml/writer code.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.toBuffer = toBuffer;
|
|
11
|
+
exports.toBase64 = toBase64;
|
|
12
|
+
exports.patchDocument = patchDocument;
|
|
13
|
+
const docx_packager_1 = require("./docx-packager");
|
|
14
|
+
const docx_reader_1 = require("./docx-reader");
|
|
15
|
+
const internal_utils_1 = require("./internal-utils");
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Document IO (toBuffer / toBase64)
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/** Package a DocxDocument model to DOCX bytes. */
|
|
20
|
+
async function toBuffer(doc, compressionLevel) {
|
|
21
|
+
return (0, docx_packager_1.packageDocx)(doc, compressionLevel);
|
|
22
|
+
}
|
|
23
|
+
/** Package a DocxDocument model to base64 string. */
|
|
24
|
+
async function toBase64(doc, compressionLevel) {
|
|
25
|
+
const bytes = await toBuffer(doc, compressionLevel);
|
|
26
|
+
return (0, internal_utils_1.bytesToBase64)(bytes);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Read an existing DOCX file, replace placeholders with content, and produce a new DOCX.
|
|
30
|
+
*
|
|
31
|
+
* Placeholders are strings like `{{name}}` embedded in the document text.
|
|
32
|
+
* They may span across multiple runs — the patcher handles cross-run matching.
|
|
33
|
+
*
|
|
34
|
+
* Supported patch content types:
|
|
35
|
+
* - `text` — simple text replacement (preserves formatting of the first run)
|
|
36
|
+
* - `paragraph` — replaces the entire paragraph containing the placeholder
|
|
37
|
+
* - `table` — replaces the entire paragraph with a table
|
|
38
|
+
* - `image` — replaces the placeholder with an inline image
|
|
39
|
+
*
|
|
40
|
+
* @param buffer - The source DOCX file as a Uint8Array.
|
|
41
|
+
* @param patches - Array of patch operations to apply.
|
|
42
|
+
* @param options - Optional compression settings.
|
|
43
|
+
* @returns New DOCX file as a Uint8Array.
|
|
44
|
+
*/
|
|
45
|
+
async function patchDocument(buffer, patches, options) {
|
|
46
|
+
const doc = await (0, docx_reader_1.readDocx)(buffer);
|
|
47
|
+
// Build lookup map for quick placeholder matching
|
|
48
|
+
const patchMap = new Map();
|
|
49
|
+
for (const patch of patches) {
|
|
50
|
+
patchMap.set(patch.placeholder, patch);
|
|
51
|
+
}
|
|
52
|
+
// Process body content
|
|
53
|
+
const newBody = [];
|
|
54
|
+
for (const block of doc.body) {
|
|
55
|
+
if (block.type === "paragraph") {
|
|
56
|
+
const result = patchParagraph(block, patchMap);
|
|
57
|
+
if (result) {
|
|
58
|
+
if (Array.isArray(result)) {
|
|
59
|
+
newBody.push(...result);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
newBody.push(result);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (block.type === "table") {
|
|
67
|
+
patchTable(block, patchMap);
|
|
68
|
+
newBody.push(block);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
newBody.push(block);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Patch headers
|
|
75
|
+
if (doc.headers) {
|
|
76
|
+
for (const [, headerDef] of doc.headers) {
|
|
77
|
+
patchHeaderFooterContent(headerDef.content, patchMap);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Patch footers
|
|
81
|
+
if (doc.footers) {
|
|
82
|
+
for (const [, footerDef] of doc.footers) {
|
|
83
|
+
patchHeaderFooterContent(footerDef.content, patchMap);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Add any new images from patches
|
|
87
|
+
const images = doc.images ? [...doc.images] : [];
|
|
88
|
+
for (const patch of patches) {
|
|
89
|
+
if (patch.content.type === "image") {
|
|
90
|
+
const imgContent = patch.content;
|
|
91
|
+
const existing = images.find(i => i.fileName === imgContent.image.fileName);
|
|
92
|
+
if (!existing) {
|
|
93
|
+
images.push(imgContent.image);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const patched = {
|
|
98
|
+
...doc,
|
|
99
|
+
body: newBody,
|
|
100
|
+
images: images.length > 0 ? images : undefined
|
|
101
|
+
};
|
|
102
|
+
return (0, docx_packager_1.packageDocx)(patched, options?.compressionLevel);
|
|
103
|
+
}
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// Internal helpers
|
|
106
|
+
// =============================================================================
|
|
107
|
+
/** Extract concatenated plain text from a paragraph's runs. */
|
|
108
|
+
function paragraphText(para) {
|
|
109
|
+
let t = "";
|
|
110
|
+
for (const child of para.children) {
|
|
111
|
+
if ("content" in child && Array.isArray(child.content)) {
|
|
112
|
+
for (const c of child.content) {
|
|
113
|
+
if ("type" in c && c.type === "text" && "text" in c) {
|
|
114
|
+
t += c.text;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return t;
|
|
120
|
+
}
|
|
121
|
+
/** Replace text within a single paragraph. */
|
|
122
|
+
function replaceInParagraph(para, search, replacement) {
|
|
123
|
+
for (const child of para.children) {
|
|
124
|
+
if (!("content" in child) || !Array.isArray(child.content)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const c of child.content) {
|
|
128
|
+
if (!("type" in c) || c.type !== "text" || !("text" in c)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const before = c.text;
|
|
132
|
+
if (before.includes(search)) {
|
|
133
|
+
c.text = before.replaceAll(search, replacement);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Cross-run replacement fallback
|
|
138
|
+
const fullText = paragraphText(para);
|
|
139
|
+
if (fullText.includes(search)) {
|
|
140
|
+
const newText = fullText.replaceAll(search, replacement);
|
|
141
|
+
let placed = false;
|
|
142
|
+
for (const child of para.children) {
|
|
143
|
+
if (!("content" in child) || !Array.isArray(child.content)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
for (const c of child.content) {
|
|
147
|
+
if (!("type" in c) || c.type !== "text" || !("text" in c)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (!placed) {
|
|
151
|
+
c.text = newText;
|
|
152
|
+
placed = true;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
c.text = "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Patch a paragraph — returns replacement content or null to remove. */
|
|
162
|
+
function patchParagraph(para, patchMap) {
|
|
163
|
+
const text = paragraphText(para);
|
|
164
|
+
for (const [placeholder, patch] of patchMap) {
|
|
165
|
+
if (!text.includes(placeholder)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
switch (patch.content.type) {
|
|
169
|
+
case "text": {
|
|
170
|
+
replaceInParagraph(para, placeholder, patch.content.text);
|
|
171
|
+
return para;
|
|
172
|
+
}
|
|
173
|
+
case "paragraph": {
|
|
174
|
+
return patch.content.children;
|
|
175
|
+
}
|
|
176
|
+
case "table": {
|
|
177
|
+
return patch.content.table;
|
|
178
|
+
}
|
|
179
|
+
case "image": {
|
|
180
|
+
const img = patch.content.image;
|
|
181
|
+
const rId = img.rId ?? `rId_img_${img.fileName}`;
|
|
182
|
+
const imgContent = {
|
|
183
|
+
type: "image",
|
|
184
|
+
rId,
|
|
185
|
+
width: patch.content.width,
|
|
186
|
+
height: patch.content.height,
|
|
187
|
+
altText: img.fileName,
|
|
188
|
+
name: img.fileName
|
|
189
|
+
};
|
|
190
|
+
const newPara = {
|
|
191
|
+
type: "paragraph",
|
|
192
|
+
properties: para.properties,
|
|
193
|
+
children: [{ content: [imgContent] }]
|
|
194
|
+
};
|
|
195
|
+
return newPara;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return para;
|
|
200
|
+
}
|
|
201
|
+
/** Patch text inside table cells recursively. */
|
|
202
|
+
function patchTable(table, patchMap) {
|
|
203
|
+
for (const row of table.rows) {
|
|
204
|
+
for (const cell of row.cells) {
|
|
205
|
+
const newContent = [];
|
|
206
|
+
for (const block of cell.content) {
|
|
207
|
+
if (block.type === "paragraph") {
|
|
208
|
+
const result = patchParagraph(block, patchMap);
|
|
209
|
+
if (result) {
|
|
210
|
+
if (Array.isArray(result)) {
|
|
211
|
+
newContent.push(...result);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
newContent.push(result);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else if (block.type === "table") {
|
|
219
|
+
patchTable(block, patchMap);
|
|
220
|
+
newContent.push(block);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
newContent.push(block);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
cell.content = newContent;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** Patch text in header/footer content. */
|
|
231
|
+
function patchHeaderFooterContent(content, patchMap) {
|
|
232
|
+
for (const child of content.children) {
|
|
233
|
+
if (child.type === "paragraph") {
|
|
234
|
+
for (const [placeholder, patch] of patchMap) {
|
|
235
|
+
if (patch.content.type === "text") {
|
|
236
|
+
const text = paragraphText(child);
|
|
237
|
+
if (text.includes(placeholder)) {
|
|
238
|
+
replaceInParagraph(child, placeholder, patch.content.text);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|