@xignature/docx-editor 1.0.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.
@@ -0,0 +1,258 @@
1
+ // src/core/utils/processTemplate.ts
2
+ import PizZip from "pizzip";
3
+ import Docxtemplater from "docxtemplater";
4
+ function processTemplate(buffer, variables, options = {}) {
5
+ const result = processTemplateDetailed(buffer, variables, options);
6
+ return result.buffer;
7
+ }
8
+ function processTemplateDetailed(buffer, variables, options = {}) {
9
+ const { nullGetter = "keep", linebreaks = true, delimiters } = options;
10
+ const warnings = [];
11
+ const replacedVariables = [];
12
+ const unreplacedVariables = [];
13
+ try {
14
+ const zip = new PizZip(buffer);
15
+ const doc = new Docxtemplater(zip, {
16
+ paragraphLoop: true,
17
+ linebreaks,
18
+ // Handle undefined tags based on option
19
+ nullGetter: (part) => {
20
+ const varName = part.value || "";
21
+ if (nullGetter === "error") {
22
+ throw new Error(`Undefined variable: ${varName}`);
23
+ }
24
+ if (nullGetter === "empty") {
25
+ unreplacedVariables.push(varName);
26
+ return "";
27
+ }
28
+ unreplacedVariables.push(varName);
29
+ return `{${varName}}`;
30
+ },
31
+ // Custom delimiters if specified (docxtemplater uses single braces by default)
32
+ delimiters: delimiters ? { start: delimiters.start || "{", end: delimiters.end || "}" } : void 0
33
+ });
34
+ Object.keys(variables).forEach((key) => {
35
+ if (variables[key] !== void 0 && variables[key] !== null) {
36
+ replacedVariables.push(key);
37
+ }
38
+ });
39
+ doc.setData(variables);
40
+ doc.render();
41
+ const outputBuffer = doc.getZip().generate({
42
+ type: "arraybuffer",
43
+ compression: "DEFLATE",
44
+ compressionOptions: { level: 6 }
45
+ });
46
+ return {
47
+ buffer: outputBuffer,
48
+ replacedVariables,
49
+ unreplacedVariables,
50
+ warnings
51
+ };
52
+ } catch (error) {
53
+ throw formatTemplateError(error);
54
+ }
55
+ }
56
+ function processTemplateAsBlob(buffer, variables, options = {}) {
57
+ const resultBuffer = processTemplate(buffer, variables, options);
58
+ return new Blob([resultBuffer], {
59
+ type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
60
+ });
61
+ }
62
+ function processTemplateAndDownload(buffer, variables, filename = "document", options = {}) {
63
+ const blob = processTemplateAsBlob(buffer, variables, options);
64
+ downloadBlob(blob, `${filename}.docx`);
65
+ }
66
+ function getTemplateTags(buffer) {
67
+ try {
68
+ const zip = new PizZip(buffer);
69
+ const doc = new Docxtemplater(zip, {
70
+ paragraphLoop: true,
71
+ linebreaks: true
72
+ });
73
+ const fullText = doc.getFullText();
74
+ return extractTagsFromText(fullText);
75
+ } catch (error) {
76
+ throw formatTemplateError(error);
77
+ }
78
+ }
79
+ function validateTemplate(buffer) {
80
+ const errors = [];
81
+ let tags = [];
82
+ try {
83
+ const zip = new PizZip(buffer);
84
+ const doc = new Docxtemplater(zip, {
85
+ paragraphLoop: true,
86
+ linebreaks: true
87
+ });
88
+ const fullText = doc.getFullText();
89
+ tags = extractTagsFromText(fullText);
90
+ const unclosedTags = findUnclosedTags(fullText);
91
+ for (const tag of unclosedTags) {
92
+ errors.push({
93
+ message: `Unclosed tag: ${tag}`,
94
+ variable: tag,
95
+ type: "parse"
96
+ });
97
+ }
98
+ return {
99
+ valid: errors.length === 0,
100
+ errors,
101
+ tags
102
+ };
103
+ } catch (error) {
104
+ errors.push(formatTemplateError(error));
105
+ return {
106
+ valid: false,
107
+ errors,
108
+ tags
109
+ };
110
+ }
111
+ }
112
+ function getMissingVariables(tags, variables) {
113
+ return tags.filter(
114
+ (tag) => !(tag in variables) || variables[tag] === void 0 || variables[tag] === null
115
+ );
116
+ }
117
+ function previewTemplate(buffer, variables) {
118
+ try {
119
+ const zip = new PizZip(buffer);
120
+ const doc = new Docxtemplater(zip, {
121
+ paragraphLoop: true,
122
+ linebreaks: true,
123
+ nullGetter: (part) => {
124
+ const varName = part.value || "";
125
+ return `[${varName}]`;
126
+ }
127
+ });
128
+ doc.setData(variables);
129
+ doc.render();
130
+ return doc.getFullText();
131
+ } catch (error) {
132
+ throw formatTemplateError(error);
133
+ }
134
+ }
135
+ function extractTagsFromText(text) {
136
+ const tags = [];
137
+ const regex = /\{([^{}]+)\}/g;
138
+ let match;
139
+ while ((match = regex.exec(text)) !== null) {
140
+ const tag = match[1].trim();
141
+ if (tag && !tags.includes(tag)) {
142
+ tags.push(tag);
143
+ }
144
+ }
145
+ return tags.sort();
146
+ }
147
+ function findUnclosedTags(text) {
148
+ const unclosed = [];
149
+ let depth = 0;
150
+ let currentTag = "";
151
+ for (const char of text) {
152
+ if (char === "{") {
153
+ depth++;
154
+ currentTag = "";
155
+ } else if (char === "}") {
156
+ depth--;
157
+ if (depth < 0) {
158
+ depth = 0;
159
+ }
160
+ } else if (depth > 0) {
161
+ currentTag += char;
162
+ }
163
+ }
164
+ if (depth > 0 && currentTag.trim()) {
165
+ unclosed.push(currentTag.trim());
166
+ }
167
+ return unclosed;
168
+ }
169
+ function isDocxTemplaterError(error) {
170
+ return "properties" in error && typeof error.properties === "object";
171
+ }
172
+ function formatTemplateError(error) {
173
+ if (error instanceof Error) {
174
+ if (isDocxTemplaterError(error) && error.properties?.errors) {
175
+ const firstError = error.properties.errors[0];
176
+ return {
177
+ message: firstError?.message || "Template processing error",
178
+ variable: firstError?.properties?.tag,
179
+ type: "render",
180
+ originalError: error
181
+ };
182
+ }
183
+ if (error.message.includes("undefined")) {
184
+ const match = error.message.match(/undefined (?:variable|tag):\s*(\S+)/i);
185
+ return {
186
+ message: error.message,
187
+ variable: match ? match[1] : void 0,
188
+ type: "undefined",
189
+ originalError: error
190
+ };
191
+ }
192
+ if (error.message.includes("parse") || error.message.includes("unclosed") || error.message.includes("syntax")) {
193
+ return {
194
+ message: error.message,
195
+ type: "parse",
196
+ originalError: error
197
+ };
198
+ }
199
+ return {
200
+ message: error.message,
201
+ type: "unknown",
202
+ originalError: error
203
+ };
204
+ }
205
+ return {
206
+ message: String(error),
207
+ type: "unknown"
208
+ };
209
+ }
210
+ function downloadBlob(blob, filename) {
211
+ const url = URL.createObjectURL(blob);
212
+ const link = document.createElement("a");
213
+ link.href = url;
214
+ link.download = filename;
215
+ document.body.appendChild(link);
216
+ link.click();
217
+ document.body.removeChild(link);
218
+ URL.revokeObjectURL(url);
219
+ }
220
+ function processTemplateAdvanced(buffer, data, options = {}) {
221
+ const { linebreaks = true, delimiters } = options;
222
+ try {
223
+ const zip = new PizZip(buffer);
224
+ const doc = new Docxtemplater(zip, {
225
+ paragraphLoop: true,
226
+ linebreaks,
227
+ delimiters: delimiters ? { start: delimiters.start || "{", end: delimiters.end || "}" } : void 0
228
+ });
229
+ doc.setData(data);
230
+ doc.render();
231
+ return doc.getZip().generate({
232
+ type: "arraybuffer",
233
+ compression: "DEFLATE"
234
+ });
235
+ } catch (error) {
236
+ throw formatTemplateError(error);
237
+ }
238
+ }
239
+ function createTemplateProcessor(defaultOptions = {}) {
240
+ return (buffer, variables) => {
241
+ return processTemplate(buffer, variables, defaultOptions);
242
+ };
243
+ }
244
+ var processTemplate_default = processTemplate;
245
+
246
+ export {
247
+ processTemplate,
248
+ processTemplateDetailed,
249
+ processTemplateAsBlob,
250
+ processTemplateAndDownload,
251
+ getTemplateTags,
252
+ validateTemplate,
253
+ getMissingVariables,
254
+ previewTemplate,
255
+ processTemplateAdvanced,
256
+ createTemplateProcessor,
257
+ processTemplate_default
258
+ };