md2gost 1.3.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/LICENSE +21 -0
- package/README.md +926 -0
- package/assets/run.ps1 +61 -0
- package/assets/styles.xml +1140 -0
- package/assets/template.dotm +0 -0
- package/dist/cli.js +92 -0
- package/dist/cli.js.map +6 -0
- package/dist/index.cjs +2165 -0
- package/dist/index.cjs.map +6 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.mjs +2130 -0
- package/dist/index.mjs.map +6 -0
- package/package.json +227 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
MDRenderError: () => MDRenderError,
|
|
34
|
+
default: () => renderMarkdown
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
var import_path4 = __toESM(require("path"));
|
|
38
|
+
var import_url = require("url");
|
|
39
|
+
|
|
40
|
+
// src/main.ts
|
|
41
|
+
var import_path3 = __toESM(require("path"));
|
|
42
|
+
|
|
43
|
+
// src/doc.ts
|
|
44
|
+
var Doc = class {
|
|
45
|
+
nodes = [];
|
|
46
|
+
rainbow = false;
|
|
47
|
+
numberingLazy = false;
|
|
48
|
+
numberingSections = false;
|
|
49
|
+
numberingAutoprefix = true;
|
|
50
|
+
backtickMono = "italic";
|
|
51
|
+
title;
|
|
52
|
+
author;
|
|
53
|
+
etime;
|
|
54
|
+
ctime;
|
|
55
|
+
mtime;
|
|
56
|
+
hyphenation = false;
|
|
57
|
+
headings = {
|
|
58
|
+
h1: { size: 14, spacing: { before: 18, after: 4 }, indent_full: false, uppercase: false },
|
|
59
|
+
h3: { size: 14, spacing: { before: 8, after: 4 }, indent_full: false, uppercase: false },
|
|
60
|
+
h2: { size: 14, spacing: { before: 8, after: 4 }, indent_full: false, uppercase: false },
|
|
61
|
+
h4: { size: 14, spacing: { before: 8, after: 4 }, indent_full: false, uppercase: false },
|
|
62
|
+
h5: { size: 14, spacing: { before: 8, after: 4 }, indent_full: false, uppercase: false },
|
|
63
|
+
h6: { size: 14, spacing: { before: 8, after: 4 }, indent_full: false, uppercase: false }
|
|
64
|
+
};
|
|
65
|
+
text = {
|
|
66
|
+
size: 14,
|
|
67
|
+
line_spacing: 1.5,
|
|
68
|
+
indent: 1.25,
|
|
69
|
+
spacing: { after: 8 }
|
|
70
|
+
};
|
|
71
|
+
table = {
|
|
72
|
+
title: {
|
|
73
|
+
style: "normal",
|
|
74
|
+
size: void 0
|
|
75
|
+
},
|
|
76
|
+
heading: {
|
|
77
|
+
style: "normal",
|
|
78
|
+
align: "center"
|
|
79
|
+
},
|
|
80
|
+
spacing: { before: void 0, after: void 0 },
|
|
81
|
+
text: {
|
|
82
|
+
size: 12,
|
|
83
|
+
line_spacing: 1.25
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
code = {
|
|
87
|
+
title: {
|
|
88
|
+
style: "normal",
|
|
89
|
+
size: void 0
|
|
90
|
+
},
|
|
91
|
+
spacing: { before: void 0, after: void 0 },
|
|
92
|
+
highlight: false,
|
|
93
|
+
text: { size: 12 }
|
|
94
|
+
};
|
|
95
|
+
list = {
|
|
96
|
+
ordered: { style: "bracket" },
|
|
97
|
+
unordered: { style: "dash" },
|
|
98
|
+
autopunctuation: true
|
|
99
|
+
};
|
|
100
|
+
img = {
|
|
101
|
+
spacing: { before: void 0, after: void 0 },
|
|
102
|
+
text: { size: void 0 }
|
|
103
|
+
};
|
|
104
|
+
appendText(text) {
|
|
105
|
+
this.nodes.push({ type: "text", text });
|
|
106
|
+
}
|
|
107
|
+
appendTitle(text, level) {
|
|
108
|
+
this.nodes.push({ type: "title", text, level });
|
|
109
|
+
}
|
|
110
|
+
appendNode(node) {
|
|
111
|
+
this.nodes.push(node);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
function tableRow(...items) {
|
|
115
|
+
return items.map((v) => ({ type: "text", text: v }));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/parser.ts
|
|
119
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
120
|
+
|
|
121
|
+
// src/utils.ts
|
|
122
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
123
|
+
function choice(...options) {
|
|
124
|
+
return options[randomInt(options.length)];
|
|
125
|
+
}
|
|
126
|
+
function randomInt(maxmin, max, rnd = Math.random) {
|
|
127
|
+
if (max != void 0)
|
|
128
|
+
return Math.floor(rnd() * (maxmin - max)) + max;
|
|
129
|
+
return Math.floor(rnd() * maxmin);
|
|
130
|
+
}
|
|
131
|
+
function trimEnd(str, ...chs) {
|
|
132
|
+
if (!chs || chs.length == 0) return str.trimEnd();
|
|
133
|
+
let trimmed = false;
|
|
134
|
+
do {
|
|
135
|
+
trimmed = false;
|
|
136
|
+
for (const ch of chs)
|
|
137
|
+
while (str.endsWith(ch)) {
|
|
138
|
+
str = str.slice(0, -ch.length);
|
|
139
|
+
trimmed = true;
|
|
140
|
+
}
|
|
141
|
+
} while (trimmed);
|
|
142
|
+
return str;
|
|
143
|
+
}
|
|
144
|
+
function trimStart(str, ...chs) {
|
|
145
|
+
if (!chs || chs.length == 0) return str.trimStart();
|
|
146
|
+
let trimmed = false;
|
|
147
|
+
do {
|
|
148
|
+
trimmed = false;
|
|
149
|
+
for (const ch of chs)
|
|
150
|
+
while (str.startsWith(ch)) {
|
|
151
|
+
str = str.slice(ch.length);
|
|
152
|
+
trimmed = true;
|
|
153
|
+
}
|
|
154
|
+
} while (trimmed);
|
|
155
|
+
return str;
|
|
156
|
+
}
|
|
157
|
+
function toCapitalCase(str) {
|
|
158
|
+
return str.slice(0, 1).toUpperCase() + str.slice(1);
|
|
159
|
+
}
|
|
160
|
+
async function checkIfFileIsBlocked(path5) {
|
|
161
|
+
let file;
|
|
162
|
+
try {
|
|
163
|
+
file = await import_promises.default.open(path5, "r+");
|
|
164
|
+
return false;
|
|
165
|
+
} catch (err) {
|
|
166
|
+
if (!err) return false;
|
|
167
|
+
if (err.code === "EBUSY" || err.code === "EACCES" || err.code === "EPERM") return true;
|
|
168
|
+
if (err.code === "ENOENT") return false;
|
|
169
|
+
throw err;
|
|
170
|
+
} finally {
|
|
171
|
+
if (file) await file.close();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function hslToHex(h, s, l) {
|
|
175
|
+
l /= 100;
|
|
176
|
+
const a = s * Math.min(l, 1 - l) / 100;
|
|
177
|
+
const f = (n) => {
|
|
178
|
+
const k = (n + h / 30) % 12;
|
|
179
|
+
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
180
|
+
return Math.round(255 * color).toString(16).padStart(2, "0");
|
|
181
|
+
};
|
|
182
|
+
return `${f(0)}${f(8)}${f(4)}`;
|
|
183
|
+
}
|
|
184
|
+
function repeat(n, v) {
|
|
185
|
+
if (v === void 0) v = (i) => i;
|
|
186
|
+
return new Array(n).fill(null).map((_, i) => v instanceof Function ? v(i) : v);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/parser.ts
|
|
190
|
+
var import_path = __toESM(require("path"));
|
|
191
|
+
async function parseMD(file, logwarn = console.warn) {
|
|
192
|
+
const lines = (await import_promises2.default.readFile(file, { encoding: "utf8" })).split("\n");
|
|
193
|
+
const doc = new Doc();
|
|
194
|
+
try {
|
|
195
|
+
doc.title = toCapitalCase(trimEnd(import_path.default.parse(file).name, ".g"));
|
|
196
|
+
const stats = await import_promises2.default.stat(file);
|
|
197
|
+
doc.ctime = stats.birthtime;
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
function parseList(text, parts, ordered, level = 0) {
|
|
201
|
+
const startIndex = isFinite(parseInt(parts[0])) ? parseInt(parts[0]) : 1;
|
|
202
|
+
const mark = ordered ? parts[1] == "." ? "." : ")" : parts[1] == "*" ? "*" : "-";
|
|
203
|
+
const node = { type: "list", ordered, mark, startIndex, items: [{ type: "listItem", text }] };
|
|
204
|
+
const P = ordered ? "1)" : "*";
|
|
205
|
+
function skipEmptyLines() {
|
|
206
|
+
let emptyFound = false;
|
|
207
|
+
for (let i = lineI; i < lines.length; i++) {
|
|
208
|
+
let ln = parseLine(lines[i]);
|
|
209
|
+
if (ln.prefix == " ") ln = parseLine(ln.text);
|
|
210
|
+
if (ln.prefix == "" && ln.text == "") {
|
|
211
|
+
emptyFound = true;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (ln.prefix == "" && !emptyFound) {
|
|
215
|
+
lineI = i;
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (ln.prefix == "*" || ln.prefix == "1)") {
|
|
219
|
+
lineI = i;
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
while (lineI < lines.length) {
|
|
227
|
+
if (skipEmptyLines()) break;
|
|
228
|
+
let ln = parseLine(lines[lineI]);
|
|
229
|
+
const last = node.items.at(-1);
|
|
230
|
+
if (ln.level == level) {
|
|
231
|
+
if (ln.prefix == " ") ln = parseLine(ln.text);
|
|
232
|
+
if (ln.prefix == "" && last?.type == "listItem")
|
|
233
|
+
last.text += "\n" + ln.text;
|
|
234
|
+
else if (ln.prefix == P)
|
|
235
|
+
node.items.push({ type: "listItem", text: ln.text });
|
|
236
|
+
else break;
|
|
237
|
+
} else if (ln.level > level) {
|
|
238
|
+
if (ln.level == level + 1) ln = parseLine(ln.text);
|
|
239
|
+
if ((ln.prefix == "" || ln.prefix == " ") && last?.type == "listItem")
|
|
240
|
+
last.text += "\n" + ln.text;
|
|
241
|
+
else if (ln.prefix == "*" || ln.prefix == "1)") {
|
|
242
|
+
lineI++;
|
|
243
|
+
node.items.push(parseList(ln.text, ln.parts, ln.prefix == "1)", level + 1));
|
|
244
|
+
continue;
|
|
245
|
+
} else break;
|
|
246
|
+
} else break;
|
|
247
|
+
lineI++;
|
|
248
|
+
}
|
|
249
|
+
return node;
|
|
250
|
+
}
|
|
251
|
+
function parseImg(parts) {
|
|
252
|
+
const text = parts[0].replaceAll("\\n", "\n").trim() || void 0;
|
|
253
|
+
const size = parts[2];
|
|
254
|
+
let width = null;
|
|
255
|
+
let height = null;
|
|
256
|
+
if (size) {
|
|
257
|
+
const s = size.split("x");
|
|
258
|
+
const w = parseInt(s[0] || "");
|
|
259
|
+
const h = parseInt(s[1] || "");
|
|
260
|
+
if (isFinite(w)) width = w;
|
|
261
|
+
if (isFinite(h)) height = h;
|
|
262
|
+
}
|
|
263
|
+
const src = trimEnd(trimStart(parts[1], "<"), ">");
|
|
264
|
+
return { type: "image", text, src, width, height };
|
|
265
|
+
}
|
|
266
|
+
function parseCode(text) {
|
|
267
|
+
const header = text.split(" ");
|
|
268
|
+
const title = header.slice(1).join(" ").trim() || void 0;
|
|
269
|
+
const node = { type: "code", lang: header[0], title, code: "" };
|
|
270
|
+
text = "";
|
|
271
|
+
while (lineI < lines.length) {
|
|
272
|
+
let ln = lines[lineI++];
|
|
273
|
+
if (ln.startsWith("```")) break;
|
|
274
|
+
text += "\n" + ln;
|
|
275
|
+
}
|
|
276
|
+
node.code = text.trim();
|
|
277
|
+
return node;
|
|
278
|
+
}
|
|
279
|
+
function parseSection(text) {
|
|
280
|
+
const match = /from\s+(\d+)/.exec(text);
|
|
281
|
+
const num = match ? parseInt(match[1] || "") : NaN;
|
|
282
|
+
return { type: "sectionBreak", pageStart: isFinite(num) ? num : null };
|
|
283
|
+
}
|
|
284
|
+
class RuleError extends Error {
|
|
285
|
+
}
|
|
286
|
+
;
|
|
287
|
+
function apllyRule(text) {
|
|
288
|
+
text = text.trim().replaceAll(/\s+/g, " ");
|
|
289
|
+
const textl = text.toLowerCase();
|
|
290
|
+
const rules = {
|
|
291
|
+
"highlight code": (v) => doc.code.highlight = true,
|
|
292
|
+
// deprecated
|
|
293
|
+
"rainbow": (v) => doc.rainbow = true,
|
|
294
|
+
"title": (v) => doc.title = v,
|
|
295
|
+
"author": (v) => doc.author = v,
|
|
296
|
+
"etime": (v) => doc.etime = tryParseInt(v),
|
|
297
|
+
"ctime": (v) => doc.ctime = tryParseDate(v),
|
|
298
|
+
"mtime": (v) => doc.mtime = tryParseDate(v),
|
|
299
|
+
"numbering lazy": (v) => {
|
|
300
|
+
choices(v, "", "on", "off");
|
|
301
|
+
doc.numberingLazy = !v || v == "on";
|
|
302
|
+
},
|
|
303
|
+
"numbering sections": (v) => {
|
|
304
|
+
choices(v, "", "on", "off");
|
|
305
|
+
doc.numberingSections = !v || v == "on";
|
|
306
|
+
},
|
|
307
|
+
"numbering autoprefix": (v) => {
|
|
308
|
+
choices(v, "", "on", "off");
|
|
309
|
+
doc.numberingAutoprefix = v == "on";
|
|
310
|
+
},
|
|
311
|
+
"backtick_mono": (v) => doc.backtickMono = choices(v, "italic", "off", "on", "outline"),
|
|
312
|
+
"hyphenation": (v) => doc.hyphenation = true,
|
|
313
|
+
"table title style": (v) => doc.table.title.style = choices(v, "normal", "bold", "italic"),
|
|
314
|
+
"table title size": (v) => doc.table.title.size = tryParseInt(v),
|
|
315
|
+
"table spacing before": (v) => doc.table.spacing.before = tryParseInt(v),
|
|
316
|
+
"table spacing after": (v) => doc.table.spacing.after = tryParseInt(v),
|
|
317
|
+
"table heading style": (v) => doc.table.heading.style = choices(v, "normal", "bold", "italic"),
|
|
318
|
+
"table heading align": (v) => doc.table.heading.align = choices(v, "left", "center", "right"),
|
|
319
|
+
"table text size": (v) => doc.table.text.size = tryParseInt(v),
|
|
320
|
+
"table text line_spacing": (v) => doc.table.text.line_spacing = tryParseFloat(v),
|
|
321
|
+
"code title style": (v) => doc.code.title.style = choices(v, "normal", "bold", "italic"),
|
|
322
|
+
"code title size": (v) => doc.code.title.size = tryParseInt(v),
|
|
323
|
+
"code spacing before": (v) => doc.code.spacing.before = tryParseInt(v),
|
|
324
|
+
"code spacing after": (v) => doc.code.spacing.after = tryParseInt(v),
|
|
325
|
+
"code highlight": (v) => {
|
|
326
|
+
choices(v, "", "on", "off");
|
|
327
|
+
doc.code.highlight = !v || v == "on";
|
|
328
|
+
},
|
|
329
|
+
"code text size": (v) => doc.code.text.size = tryParseInt(v),
|
|
330
|
+
"list ordered style": (v) => doc.list.ordered.style = choices(v, "bracket", "dot", "keep"),
|
|
331
|
+
"list unordered style": (v) => doc.list.unordered.style = choices(v, "dash", "bullet", "keep"),
|
|
332
|
+
"list autopunctuation": (v) => {
|
|
333
|
+
choices(v, "", "on", "off");
|
|
334
|
+
doc.list.autopunctuation = v == "on";
|
|
335
|
+
},
|
|
336
|
+
"headings alt_style_1": (v) => {
|
|
337
|
+
for (let i = 1; i <= 6; i++) {
|
|
338
|
+
doc.headings[`h${i}`].indent_full = true;
|
|
339
|
+
doc.headings[`h${i}`].spacing.after = 10;
|
|
340
|
+
doc.headings[`h${i}`].spacing.before = 15;
|
|
341
|
+
}
|
|
342
|
+
doc.headings.h1.size = 18;
|
|
343
|
+
doc.headings.h1.uppercase = true;
|
|
344
|
+
doc.headings.h1.spacing.before = 0;
|
|
345
|
+
doc.headings.h2.size = 16;
|
|
346
|
+
},
|
|
347
|
+
"text size": (v) => doc.text.size = tryParseInt(v),
|
|
348
|
+
"text line_spacing": (v) => doc.text.line_spacing = tryParseFloat(v),
|
|
349
|
+
"text indent": (v) => doc.text.indent = tryParseFloat(v),
|
|
350
|
+
"text spacing after": (v) => doc.text.spacing.after = tryParseInt(v),
|
|
351
|
+
"img text size": (v) => doc.img.text.size = tryParseInt(v),
|
|
352
|
+
"img spacing before": (v) => doc.img.spacing.before = tryParseInt(v),
|
|
353
|
+
"img spacing after": (v) => doc.img.spacing.after = tryParseInt(v)
|
|
354
|
+
};
|
|
355
|
+
const reRules = [
|
|
356
|
+
{
|
|
357
|
+
re: /^(headings (h[1-6])(\+?) (size|spacing (before|after)|uppercase|indent))(.*)/,
|
|
358
|
+
n: (m) => ({ rule: m[1], value: (m.at(-1) || "").trim() }),
|
|
359
|
+
f(m) {
|
|
360
|
+
const level = parseInt(m[2][1]);
|
|
361
|
+
const plus = m[3] == "+";
|
|
362
|
+
const property = m[4];
|
|
363
|
+
const value = (m.at(-1) || "").trim();
|
|
364
|
+
for (let i = level; i <= (plus ? 6 : level); i++) {
|
|
365
|
+
const h = doc.headings[`h${i}`];
|
|
366
|
+
if (property == "size") h.size = tryParseInt(value);
|
|
367
|
+
else if (property == "spacing before") h.spacing.before = tryParseInt(value);
|
|
368
|
+
else if (property == "spacing after") h.spacing.after = tryParseInt(value);
|
|
369
|
+
else if (property == "uppercase") {
|
|
370
|
+
choices(value, "", "on", "off");
|
|
371
|
+
h.uppercase = !value || value == "on";
|
|
372
|
+
} else if (property == "indent") h.indent_full = choices(value, "first_line", "left") == "left";
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
];
|
|
377
|
+
const rulePrefix = Object.keys(rules).find(
|
|
378
|
+
(prefix) => textl.startsWith(prefix) && !textl.slice(prefix.length)[0]?.trim()
|
|
379
|
+
);
|
|
380
|
+
const reRule = rulePrefix ? void 0 : reRules.map(({ re, f, n }) => ({ f, n, m: re.exec(textl) })).find(({ m }) => !!m);
|
|
381
|
+
let applyRule = rulePrefix ? () => rules[rulePrefix](text.slice(rulePrefix.length).trim()) : reRule ? () => reRule.f(reRule.m) : void 0;
|
|
382
|
+
if (applyRule) {
|
|
383
|
+
try {
|
|
384
|
+
applyRule();
|
|
385
|
+
} catch (e) {
|
|
386
|
+
let rule = rulePrefix;
|
|
387
|
+
let value = rulePrefix && text.slice(rulePrefix.length);
|
|
388
|
+
if (reRule) {
|
|
389
|
+
const n = reRule.n(reRule.m);
|
|
390
|
+
rule = n.rule;
|
|
391
|
+
value = n.value;
|
|
392
|
+
}
|
|
393
|
+
if (e instanceof RuleError) logwarn(`Rule "${rule}" wrong value: "${value}". ${e.message}`);
|
|
394
|
+
else throw e;
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
logwarn(`Wrong rule: "${text}"`);
|
|
398
|
+
}
|
|
399
|
+
function tryParseInt(v) {
|
|
400
|
+
const num = parseInt(v);
|
|
401
|
+
if (!isFinite(num)) throw new RuleError("Only integers are allowed");
|
|
402
|
+
return num;
|
|
403
|
+
}
|
|
404
|
+
function tryParseFloat(v) {
|
|
405
|
+
const num = parseFloat(v);
|
|
406
|
+
if (!isFinite(num)) throw new RuleError("Only integers and floats are allowed");
|
|
407
|
+
return num;
|
|
408
|
+
}
|
|
409
|
+
function tryParseDate(v) {
|
|
410
|
+
const date = new Date(v);
|
|
411
|
+
if (!isFinite(date.valueOf())) throw new RuleError("Only ISO 8601 date is allowed");
|
|
412
|
+
return date;
|
|
413
|
+
}
|
|
414
|
+
function choices(v, ...vars) {
|
|
415
|
+
if (vars.includes(v)) return v;
|
|
416
|
+
throw new RuleError("Allowed: " + vars.join(", "));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function skipComment() {
|
|
420
|
+
while (lineI - 1 < lines.length && !lines[lineI - 1].includes("-->"))
|
|
421
|
+
lineI++;
|
|
422
|
+
}
|
|
423
|
+
let lineI = 0;
|
|
424
|
+
while (lineI < lines.length) {
|
|
425
|
+
const line = lines[lineI++];
|
|
426
|
+
const { prefix, text, parts } = parseLine(line);
|
|
427
|
+
switch (prefix) {
|
|
428
|
+
case "#":
|
|
429
|
+
doc.appendTitle(text, 1);
|
|
430
|
+
break;
|
|
431
|
+
case "##":
|
|
432
|
+
doc.appendTitle(text, 2);
|
|
433
|
+
break;
|
|
434
|
+
case "###":
|
|
435
|
+
doc.appendTitle(text, 3);
|
|
436
|
+
break;
|
|
437
|
+
case "####":
|
|
438
|
+
doc.appendTitle(text, 4);
|
|
439
|
+
break;
|
|
440
|
+
case "#####":
|
|
441
|
+
doc.appendTitle(text, 5);
|
|
442
|
+
break;
|
|
443
|
+
case "######":
|
|
444
|
+
doc.appendTitle(text, 6);
|
|
445
|
+
break;
|
|
446
|
+
case "*":
|
|
447
|
+
doc.appendNode(parseList(text, parts, false));
|
|
448
|
+
break;
|
|
449
|
+
case "1)":
|
|
450
|
+
doc.appendNode(parseList(text, parts, true));
|
|
451
|
+
break;
|
|
452
|
+
case "Img":
|
|
453
|
+
doc.appendNode(parseImg(parts));
|
|
454
|
+
break;
|
|
455
|
+
case "Code":
|
|
456
|
+
doc.appendNode(parseCode(text));
|
|
457
|
+
break;
|
|
458
|
+
case "Comment":
|
|
459
|
+
skipComment();
|
|
460
|
+
break;
|
|
461
|
+
case "!!section":
|
|
462
|
+
doc.appendNode(parseSection(text));
|
|
463
|
+
break;
|
|
464
|
+
case "!!rule":
|
|
465
|
+
apllyRule(text);
|
|
466
|
+
break;
|
|
467
|
+
case "---":
|
|
468
|
+
doc.appendNode({ type: "pageBreak" });
|
|
469
|
+
break;
|
|
470
|
+
case "":
|
|
471
|
+
case " ":
|
|
472
|
+
const last = doc.nodes.at(-1);
|
|
473
|
+
if (line.trim() != "" && last?.type == "text") {
|
|
474
|
+
if (last.text != "") last.text += "\n";
|
|
475
|
+
last.text += line.trim();
|
|
476
|
+
} else doc.appendText(line.trim());
|
|
477
|
+
break;
|
|
478
|
+
default:
|
|
479
|
+
prefix;
|
|
480
|
+
throw new Error("switch default");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
doc.nodes = doc.nodes.filter((n) => n.type != "text" || n.text != "");
|
|
484
|
+
findDocs(doc.nodes, logwarn);
|
|
485
|
+
findTables(doc.nodes);
|
|
486
|
+
findPageBreaks(doc.nodes);
|
|
487
|
+
return doc;
|
|
488
|
+
}
|
|
489
|
+
function parseLine(line) {
|
|
490
|
+
let level = 0;
|
|
491
|
+
while (line.startsWith(" ") || line.startsWith(" ")) {
|
|
492
|
+
if (line.startsWith(" ")) line = line = line.slice(4);
|
|
493
|
+
else if (line.startsWith(" ")) line = line.slice(1);
|
|
494
|
+
level++;
|
|
495
|
+
}
|
|
496
|
+
if (level > 0) return { prefix: " ", text: line.trim(), level, parts: [] };
|
|
497
|
+
if (/^\s*---+\s*$/.test(line)) return { prefix: "---", text: "", level, parts: [] };
|
|
498
|
+
const splited = line.trim().split(/\s/);
|
|
499
|
+
let prefix = splited[0].toLowerCase();
|
|
500
|
+
let text = splited.slice(1).join(" ");
|
|
501
|
+
let parts = [];
|
|
502
|
+
if (prefix.startsWith("!")) {
|
|
503
|
+
const m_img = /!\[(.*)\]\((.*)\)({(.*)})?/.exec(line);
|
|
504
|
+
if (m_img) return {
|
|
505
|
+
prefix: "Img",
|
|
506
|
+
text: line.trim(),
|
|
507
|
+
level,
|
|
508
|
+
parts: [m_img[1], m_img[2], m_img[4]]
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
if (prefix == "-" || prefix == "*") {
|
|
512
|
+
parts = ["", prefix];
|
|
513
|
+
prefix = "*";
|
|
514
|
+
}
|
|
515
|
+
if (prefix.endsWith(".") || prefix.endsWith(")")) {
|
|
516
|
+
const index = parseInt(prefix.slice(0, -1));
|
|
517
|
+
if (isFinite(index)) {
|
|
518
|
+
parts = [`${index}`, prefix.at(-1) || ")"];
|
|
519
|
+
prefix = "1)";
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (prefix.startsWith("```")) return { prefix: "Code", text: line.trim().slice(3), level, parts };
|
|
523
|
+
if (prefix.startsWith("<!--")) return { prefix: "Comment", text: line.trim().slice("<!--".length).trim(), level, parts };
|
|
524
|
+
if (["#", "##", "###", "####", "#####", "######", "*", "1)", "!!section", "!!rule"].includes(prefix))
|
|
525
|
+
return { prefix, text, level: 0, parts };
|
|
526
|
+
return { prefix: "", text: line.trim(), level, parts };
|
|
527
|
+
}
|
|
528
|
+
function findDocs(nodes, logwarn = console.warn) {
|
|
529
|
+
const re_doc = /^!!\(([^{}]*)\)\s*{(.*)}$/s;
|
|
530
|
+
const re_remTrailingComma = /,(\s*[}\]])/g;
|
|
531
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
532
|
+
const node = nodes[i];
|
|
533
|
+
if (node.type != "text") continue;
|
|
534
|
+
const m_doc = re_doc.exec(node.text.trimEnd().replaceAll(re_remTrailingComma, "$1"));
|
|
535
|
+
if (!m_doc) continue;
|
|
536
|
+
let dict = {};
|
|
537
|
+
try {
|
|
538
|
+
dict = JSON.parse(`{${m_doc[2]}}`);
|
|
539
|
+
} catch (x) {
|
|
540
|
+
logwarn(`Cant parse doc dict: {${m_doc[2].replaceAll("\n", " ")}}`);
|
|
541
|
+
}
|
|
542
|
+
nodes.splice(i, 1, {
|
|
543
|
+
type: "externalDoc",
|
|
544
|
+
path: trimEnd(trimStart(m_doc[1], "<", '"'), ">", '"'),
|
|
545
|
+
dict: stringifyDict(dict)
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function stringifyDict(dict) {
|
|
550
|
+
const r = {};
|
|
551
|
+
for (const key in dict) {
|
|
552
|
+
let v = dict[key];
|
|
553
|
+
if (typeof v == "string" || typeof v == "boolean" || typeof v == "number") {
|
|
554
|
+
r[key] = `${v}`;
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
if (!v) continue;
|
|
558
|
+
if (v instanceof Array) {
|
|
559
|
+
const d2 = {};
|
|
560
|
+
v.forEach((v2, i) => d2[`${i}`] = v2);
|
|
561
|
+
v = d2;
|
|
562
|
+
}
|
|
563
|
+
const d = stringifyDict(v);
|
|
564
|
+
for (const k in d)
|
|
565
|
+
r[key + "." + k] = d[k];
|
|
566
|
+
}
|
|
567
|
+
return r;
|
|
568
|
+
}
|
|
569
|
+
function findTables(nodes) {
|
|
570
|
+
const re_sep = /^(\s*:?-+:?\s*(?<!\\)\|)+\s*:?-+:?\s*$/;
|
|
571
|
+
const re_sep_oneCol = /^\|\s*:?-+:?\s*\|$/;
|
|
572
|
+
const trim = (line) => {
|
|
573
|
+
line = line.trim();
|
|
574
|
+
if (line.at(0) == "|") line = line.slice(1);
|
|
575
|
+
if (line.at(-1) == "|") line = line.slice(0, -1);
|
|
576
|
+
return line.trim();
|
|
577
|
+
};
|
|
578
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
579
|
+
const node = nodes[i];
|
|
580
|
+
if (node.type != "text") continue;
|
|
581
|
+
const lines = node.text.split("\n");
|
|
582
|
+
const offset = lines[0].includes("|") ? 0 : 1;
|
|
583
|
+
if (lines.length < 2 + offset) continue;
|
|
584
|
+
const sep = trim(lines[1 + offset]);
|
|
585
|
+
if (!re_sep.test(sep) && !re_sep_oneCol.test(lines[1 + offset])) continue;
|
|
586
|
+
const cols = sep.split("|");
|
|
587
|
+
const header = trim(lines[offset]).split(/(?<!\\)\|/).map((v) => v.trim());
|
|
588
|
+
if (header.length != cols.length) continue;
|
|
589
|
+
const align = cols.map((v) => v.trim()).map((v) => v.startsWith(":") && v.endsWith(":") ? "c" : v.endsWith(":") ? "r" : "l");
|
|
590
|
+
const rows = [tableRow(...header)];
|
|
591
|
+
for (const line of lines.slice(2 + offset)) {
|
|
592
|
+
const row = trim(line).split(/(?<!\\)\|/).map((v) => v.trim());
|
|
593
|
+
while (row.length < cols.length) row.push("");
|
|
594
|
+
rows.push(tableRow(...row));
|
|
595
|
+
}
|
|
596
|
+
const table = { type: "table", align, rows };
|
|
597
|
+
nodes.splice(i, 1, table);
|
|
598
|
+
const prev = nodes[i - 1];
|
|
599
|
+
if (offset > 0) {
|
|
600
|
+
table.title = lines[0];
|
|
601
|
+
} else if (prev?.type == "text") {
|
|
602
|
+
nodes.splice(i - 1, 1);
|
|
603
|
+
table.title = prev.text;
|
|
604
|
+
i--;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function findPageBreaks(nodes) {
|
|
609
|
+
const re_sep = /^\s*---+\s*$/;
|
|
610
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
611
|
+
const node = nodes[i];
|
|
612
|
+
if (node.type != "text") continue;
|
|
613
|
+
if (!node.text.includes("---")) continue;
|
|
614
|
+
const lines = node.text.split("\n");
|
|
615
|
+
const newNodes = [];
|
|
616
|
+
for (const line of lines) {
|
|
617
|
+
if (re_sep.test(line)) newNodes.push({ type: "pageBreak" });
|
|
618
|
+
else {
|
|
619
|
+
const last = newNodes.at(-1);
|
|
620
|
+
if (last?.type == "text") last.text += "\n" + line;
|
|
621
|
+
else newNodes.push({ type: "text", text: line, noIndent: node.noIndent, noMargin: node.noMargin });
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
nodes.splice(i, 1, ...newNodes);
|
|
625
|
+
i += newNodes.length - 1;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function runifyDoc(doc) {
|
|
629
|
+
function runifyNode(node) {
|
|
630
|
+
if ("text" in node && node.text)
|
|
631
|
+
node.text = runifyText(node.text, doc.rainbow);
|
|
632
|
+
if ("title" in node && node.title)
|
|
633
|
+
node.title = runifyText(node.title, doc.rainbow);
|
|
634
|
+
if (node.type == "table")
|
|
635
|
+
node.rows.forEach((row) => row.forEach(runifyNode));
|
|
636
|
+
if (node.type == "list")
|
|
637
|
+
node.items.forEach(runifyNode);
|
|
638
|
+
}
|
|
639
|
+
doc.nodes.forEach(runifyNode);
|
|
640
|
+
return doc;
|
|
641
|
+
}
|
|
642
|
+
var rainbowI = 0;
|
|
643
|
+
function runifyText(text, rainbow = false) {
|
|
644
|
+
return replaceAmpCodes(text).replaceAll("\n", "	\n").replaceAll(/\s*<br>\s*/g, "\n").replaceAll("\u2014", "-").replaceAll(" - ", " \u2013 ").replaceAll(/(^|[^\p{L}\d_])"([\p{L}\d_])/gu, "$1\xAB$2").replaceAll(/([\p{L}\d_])"([^\p{L}\d_]|$)/gu, "$1\xBB$2").replaceAll(/(^|\s)(\*+)($|\s)/g, (sub) => sub.replaceAll("*", "⋆")).split(/(\[[^\]]*\]\([^\)]*\))/g).map((p) => {
|
|
645
|
+
const m = /\[([^\]]*)\]\(([^\)]*)\)/.exec(p);
|
|
646
|
+
if (!m) return { text: p };
|
|
647
|
+
return { text: m[1], link: m[2] };
|
|
648
|
+
}).map((rune) => rune.text.split("\n").map((p, i) => ({
|
|
649
|
+
text: p.replaceAll(/\s+/g, " ").replaceAll(" ", "\xA0").replaceAll("	", " "),
|
|
650
|
+
linebreak: i > 0,
|
|
651
|
+
link: rune.link
|
|
652
|
+
}))).flat().map((rune) => rune.text.split("***").map((p, i, arr) => ({
|
|
653
|
+
text: p,
|
|
654
|
+
linebreak: i == 0 && rune.linebreak,
|
|
655
|
+
link: rune.link,
|
|
656
|
+
bold: i % 2 == 1 && i != arr.length - 1,
|
|
657
|
+
italic: i % 2 == 1 && i != arr.length - 1
|
|
658
|
+
}))).flat().map((rune) => rune.text.split("**").map((p, i, arr) => ({
|
|
659
|
+
text: p,
|
|
660
|
+
linebreak: i == 0 && rune.linebreak,
|
|
661
|
+
link: rune.link,
|
|
662
|
+
bold: i % 2 == 1 && i != arr.length - 1 || rune.bold,
|
|
663
|
+
italic: rune.italic
|
|
664
|
+
}))).flat().map((rune) => rune.text.split("*").map((p, i, arr) => ({
|
|
665
|
+
text: p,
|
|
666
|
+
linebreak: i == 0 && rune.linebreak,
|
|
667
|
+
link: rune.link,
|
|
668
|
+
bold: rune.bold,
|
|
669
|
+
italic: i % 2 == 1 && i != arr.length - 1 || rune.italic
|
|
670
|
+
}))).flat().map((rune) => rune.text.split("```").map((p, i, arr) => ({
|
|
671
|
+
...rune,
|
|
672
|
+
text: p,
|
|
673
|
+
linebreak: i == 0 && rune.linebreak,
|
|
674
|
+
mono: i % 2 == 1 && i != arr.length - 1
|
|
675
|
+
}))).flat().map((rune) => rune.mono ? rune : rune.text.split("`").map((p, i, arr) => ({
|
|
676
|
+
...rune,
|
|
677
|
+
text: p,
|
|
678
|
+
linebreak: i == 0 && rune.linebreak,
|
|
679
|
+
mono: i % 2 == 1 && i != arr.length - 1
|
|
680
|
+
}))).flat().map((rune) => rune.link ? [rune] : rune.text.split(/(\[!?[a-zA-Zа-яА-ЯёЁ_\d#]+\s*[+\-]?\s*\d*\])/g).map((p, i) => {
|
|
681
|
+
const m = /\[(!?([a-zA-Zа-яА-ЯёЁ_\d]+|#)(\s*[-\+]\s*\d+)?)\]/.exec(p);
|
|
682
|
+
const v = m && m[1];
|
|
683
|
+
const isVal = v?.at(0) == "!";
|
|
684
|
+
return {
|
|
685
|
+
...rune,
|
|
686
|
+
text: v ? isVal ? v.slice(1) : v : p,
|
|
687
|
+
type: v ? isVal ? "val" : "ref" : rune.type,
|
|
688
|
+
linebreak: i == 0 && rune.linebreak
|
|
689
|
+
};
|
|
690
|
+
})).flat().map((rune) => ({
|
|
691
|
+
...rune,
|
|
692
|
+
...!rune.type || rune.type == "text" ? {
|
|
693
|
+
text: rune.text.replaceAll("⋆", "*").replaceAll("​", "")
|
|
694
|
+
} : {}
|
|
695
|
+
})).map((rune) => !rainbow || rune.type && rune.type != "text" ? [rune] : rune.text.split("").map((p, i) => ({
|
|
696
|
+
...rune,
|
|
697
|
+
text: p,
|
|
698
|
+
linebreak: i == 0 && rune.linebreak,
|
|
699
|
+
color: hslToHex(rainbowI++ % 360, 100, 50)
|
|
700
|
+
}))).flat();
|
|
701
|
+
}
|
|
702
|
+
function replaceAmpCodes(text) {
|
|
703
|
+
const codes = {
|
|
704
|
+
"|": "|",
|
|
705
|
+
"­": "\xAD",
|
|
706
|
+
"«": "\xAB",
|
|
707
|
+
"»": "\xBB",
|
|
708
|
+
"‹": "\u2039",
|
|
709
|
+
"›": "\u203A",
|
|
710
|
+
"α": "\u03B1",
|
|
711
|
+
"β": "\u03B2",
|
|
712
|
+
"γ": "\u03B3",
|
|
713
|
+
"δ": "\u03B4",
|
|
714
|
+
"ε": "\u03B5",
|
|
715
|
+
"ζ": "\u03B6",
|
|
716
|
+
"η": "\u03B7",
|
|
717
|
+
"θ": "\u03B8",
|
|
718
|
+
"ι": "\u03B9",
|
|
719
|
+
"κ": "\u03BA",
|
|
720
|
+
"λ": "\u03BB",
|
|
721
|
+
"μ": "\u03BC",
|
|
722
|
+
"ν": "\u03BD",
|
|
723
|
+
"ξ": "\u03BE",
|
|
724
|
+
"ο": "\u03BF",
|
|
725
|
+
"π": "\u03C0",
|
|
726
|
+
"ρ": "\u03C1",
|
|
727
|
+
"σ": "\u03C3",
|
|
728
|
+
"τ": "\u03C4",
|
|
729
|
+
"υ": "\u03C5",
|
|
730
|
+
"φ": "\u03C6",
|
|
731
|
+
"χ": "\u03C7",
|
|
732
|
+
"ψ": "\u03C8",
|
|
733
|
+
"ω": "\u03C9",
|
|
734
|
+
"Δ": "\u0394",
|
|
735
|
+
"Σ": "\u03A3",
|
|
736
|
+
"Ω": "\u03A9",
|
|
737
|
+
"∞": "\u221E",
|
|
738
|
+
"∑": "\u2211",
|
|
739
|
+
"∏": "\u220F",
|
|
740
|
+
"√": "\u221A",
|
|
741
|
+
"∫": "\u222B",
|
|
742
|
+
"∂": "\u2202",
|
|
743
|
+
"≈": "\u2248",
|
|
744
|
+
"≠": "\u2260",
|
|
745
|
+
"<": "<",
|
|
746
|
+
">": ">",
|
|
747
|
+
"≤": "\u2264",
|
|
748
|
+
"≥": "\u2265",
|
|
749
|
+
"±": "\xB1",
|
|
750
|
+
"×": "\xD7",
|
|
751
|
+
"÷": "\xF7",
|
|
752
|
+
"©": "\xA9",
|
|
753
|
+
"®": "\xAE",
|
|
754
|
+
"™": "\u2122",
|
|
755
|
+
"§": "\xA7",
|
|
756
|
+
"¶": "\xB6",
|
|
757
|
+
"…": "\u2026",
|
|
758
|
+
"•": "\u2022",
|
|
759
|
+
"·": "\xB7",
|
|
760
|
+
"°": "\xB0",
|
|
761
|
+
"€": "\u20AC",
|
|
762
|
+
"£": "\xA3",
|
|
763
|
+
"¥": "\xA5",
|
|
764
|
+
"¢": "\xA2",
|
|
765
|
+
"¤": "\xA4",
|
|
766
|
+
"ƒ": "\u0192",
|
|
767
|
+
"‰": "\u2030"
|
|
768
|
+
};
|
|
769
|
+
for (const code in codes) {
|
|
770
|
+
if (!Object.hasOwn(codes, code)) continue;
|
|
771
|
+
const char = codes[code];
|
|
772
|
+
text = text.replaceAll(code, char);
|
|
773
|
+
}
|
|
774
|
+
return text;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// src/serializer.ts
|
|
778
|
+
var fs3 = __toESM(require("fs"));
|
|
779
|
+
var import_docx = require("docx");
|
|
780
|
+
var import_image_size = require("image-size");
|
|
781
|
+
var import_path2 = __toESM(require("path"));
|
|
782
|
+
var import_prismjs = __toESM(require("prismjs"));
|
|
783
|
+
var import_prism_clike = require("prismjs/components/prism-clike");
|
|
784
|
+
var import_prism_markup = require("prismjs/components/prism-markup");
|
|
785
|
+
var import_prism_css = require("prismjs/components/prism-css");
|
|
786
|
+
var import_prism_javascript = require("prismjs/components/prism-javascript");
|
|
787
|
+
var import_prism_typescript = require("prismjs/components/prism-typescript");
|
|
788
|
+
var import_prism_jsx = require("prismjs/components/prism-jsx");
|
|
789
|
+
var import_prism_tsx = require("prismjs/components/prism-tsx");
|
|
790
|
+
var import_prism_json = require("prismjs/components/prism-json");
|
|
791
|
+
var import_prism_bash = require("prismjs/components/prism-bash");
|
|
792
|
+
var import_prism_powershell = require("prismjs/components/prism-powershell");
|
|
793
|
+
var import_prism_python = require("prismjs/components/prism-python");
|
|
794
|
+
var import_prism_java = require("prismjs/components/prism-java");
|
|
795
|
+
var import_prism_c = require("prismjs/components/prism-c");
|
|
796
|
+
var import_prism_cpp = require("prismjs/components/prism-cpp");
|
|
797
|
+
var import_prism_csharp = require("prismjs/components/prism-csharp");
|
|
798
|
+
var import_prism_go = require("prismjs/components/prism-go");
|
|
799
|
+
var import_prism_rust = require("prismjs/components/prism-rust");
|
|
800
|
+
var import_prism_php = require("prismjs/components/prism-php");
|
|
801
|
+
var import_prism_ruby = require("prismjs/components/prism-ruby");
|
|
802
|
+
var import_prism_swift = require("prismjs/components/prism-swift");
|
|
803
|
+
var import_prism_kotlin = require("prismjs/components/prism-kotlin");
|
|
804
|
+
var import_prism_sql = require("prismjs/components/prism-sql");
|
|
805
|
+
var import_prism_yaml = require("prismjs/components/prism-yaml");
|
|
806
|
+
var import_prism_markdown = require("prismjs/components/prism-markdown");
|
|
807
|
+
var import_prism_docker = require("prismjs/components/prism-docker");
|
|
808
|
+
var import_prism_nginx = require("prismjs/components/prism-nginx");
|
|
809
|
+
var STYLE_list = "afc";
|
|
810
|
+
var STYLE_table_title = "TableCaption";
|
|
811
|
+
var STYLE_code_title = "ListingCaption";
|
|
812
|
+
var STYLE_code = "ListingCode";
|
|
813
|
+
async function serializeDocx(doc, fout, workdir, assets) {
|
|
814
|
+
const getPath = (fname) => {
|
|
815
|
+
if (process.platform == "win32" && fname[0] == "/") fname = "." + fname;
|
|
816
|
+
return import_path2.default.isAbsolute(fname) ? fname : import_path2.default.join(workdir, fname);
|
|
817
|
+
};
|
|
818
|
+
const sections = [];
|
|
819
|
+
const numbering = [];
|
|
820
|
+
const docSections = (function splitSections() {
|
|
821
|
+
const sections2 = [{ pageStart: 1, nodes: [] }];
|
|
822
|
+
for (let j = 0; j < doc.nodes.length; j++) {
|
|
823
|
+
const node = doc.nodes[j];
|
|
824
|
+
if (node.type == "sectionBreak")
|
|
825
|
+
sections2.push({ pageStart: node.pageStart, nodes: [] });
|
|
826
|
+
else
|
|
827
|
+
sections2.at(-1)?.nodes.push(node);
|
|
828
|
+
}
|
|
829
|
+
return sections2.filter((s) => s.nodes.length > 0);
|
|
830
|
+
})();
|
|
831
|
+
for (const section of docSections) {
|
|
832
|
+
let renderNode2 = function(node, prevChild, prevNode) {
|
|
833
|
+
switch (node.type) {
|
|
834
|
+
case "text":
|
|
835
|
+
return new import_docx.Paragraph({
|
|
836
|
+
children: renderText(node.text),
|
|
837
|
+
indent: node.noIndent ? { firstLine: 0 } : {},
|
|
838
|
+
...node.center ? { alignment: "center", indent: { firstLine: 0 } } : {},
|
|
839
|
+
spacing: {
|
|
840
|
+
...node.noMargin ? { after: 0 } : {},
|
|
841
|
+
...prevChild instanceof import_docx.Table ? { before: (doc.table.spacing.after ?? doc.text.spacing.after) * 20 } : {}
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
case "title":
|
|
845
|
+
if (node.level < 0 || node.level > 6) throw new Error("Wrong heading level");
|
|
846
|
+
const level = node.level == 0 ? 1 : node.level;
|
|
847
|
+
const styles = doc.headings[`h${level}`];
|
|
848
|
+
if (styles.uppercase) node.text.forEach((r) => r.text = r.text.toUpperCase());
|
|
849
|
+
return new import_docx.Paragraph({
|
|
850
|
+
children: renderText(node.text, styles.size),
|
|
851
|
+
style: `${node.level}`,
|
|
852
|
+
...node.center ? { alignment: "center", indent: { firstLine: 0 } } : {},
|
|
853
|
+
...!node.center && node.level != 0 && styles.indent_full ? { indent: { firstLine: 0, left: (0, import_docx.convertMillimetersToTwip)(12.5) } } : {},
|
|
854
|
+
spacing: {
|
|
855
|
+
before: styles.spacing.before * 20,
|
|
856
|
+
after: styles.spacing.after * 20
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
case "pageBreak":
|
|
860
|
+
if (!(prevChild instanceof import_docx.Paragraph))
|
|
861
|
+
return new import_docx.Paragraph({ children: [new import_docx.PageBreak()] });
|
|
862
|
+
prevChild.addChildElement(new import_docx.PageBreak());
|
|
863
|
+
return [];
|
|
864
|
+
case "list":
|
|
865
|
+
let renderList2 = function(node2, level2 = 0) {
|
|
866
|
+
let mark = node2.mark;
|
|
867
|
+
if (node2.ordered) mark = doc.list.ordered.style == "keep" ? mark : doc.list.ordered.style == "dot" ? "." : ")";
|
|
868
|
+
else mark = doc.list.unordered.style == "keep" ? mark : doc.list.unordered.style == "bullet" ? "*" : "-";
|
|
869
|
+
addListItemLevel(list.levels, level2, node2.startIndex, node2.items.length, !!node2.ordered, !!node2.alternativeStyle, mark);
|
|
870
|
+
for (const item of node2.items) {
|
|
871
|
+
if (item.type == "list") renderList2({ ...item, alternativeStyle: !!node2.alternativeStyle }, level2 + 1);
|
|
872
|
+
else {
|
|
873
|
+
items.push(new import_docx.Paragraph({
|
|
874
|
+
children: renderText(item.text),
|
|
875
|
+
style: STYLE_list,
|
|
876
|
+
numbering: { reference: id, level: level2 },
|
|
877
|
+
spacing: {
|
|
878
|
+
...addMargin ? { before: (doc.table.spacing.after ?? doc.text.spacing.after) * 20 } : {}
|
|
879
|
+
}
|
|
880
|
+
}));
|
|
881
|
+
addMargin = false;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var renderList = renderList2;
|
|
886
|
+
if (node.items.length == 0) return [];
|
|
887
|
+
const id = `l${numbering.length + 1}`;
|
|
888
|
+
const list = {
|
|
889
|
+
reference: id,
|
|
890
|
+
levels: []
|
|
891
|
+
};
|
|
892
|
+
numbering.push(list);
|
|
893
|
+
const items = [];
|
|
894
|
+
let addMargin = prevChild instanceof import_docx.Table;
|
|
895
|
+
renderList2(node);
|
|
896
|
+
return items;
|
|
897
|
+
case "table":
|
|
898
|
+
if (node.rows[0] && doc.table.heading.style == "italic") node.rows[0].forEach((n) => n.type == "text" ? n.text.forEach((r) => r.italic = true) : 0);
|
|
899
|
+
if (node.rows[0] && doc.table.heading.style == "bold") node.rows[0].forEach((n) => n.type == "text" ? n.text.forEach((r) => r.bold = true) : 0);
|
|
900
|
+
const spacingInner = Math.max(doc.table.spacing.after ?? doc.text.spacing.after, doc.table.spacing.before ?? 0);
|
|
901
|
+
return [
|
|
902
|
+
...node.title ? [
|
|
903
|
+
new import_docx.Paragraph({
|
|
904
|
+
children: renderText(node.title, doc.table.title.size),
|
|
905
|
+
style: STYLE_table_title,
|
|
906
|
+
...prevChild instanceof import_docx.Table ? { spacing: { before: spacingInner * 20 } } : doc.table.spacing.before ? { spacing: { before: doc.table.spacing.before * 20 } } : {}
|
|
907
|
+
})
|
|
908
|
+
] : prevChild instanceof import_docx.Table ? [
|
|
909
|
+
new import_docx.Paragraph({ spacing: { line: 20, before: spacingInner * 20, after: 0 } })
|
|
910
|
+
] : doc.table.spacing.before ? [
|
|
911
|
+
new import_docx.Paragraph({ spacing: { line: 20, before: doc.table.spacing.before * 20, after: 0 } })
|
|
912
|
+
] : [],
|
|
913
|
+
new import_docx.Table({
|
|
914
|
+
// width: { type: "pct", size: 100 },
|
|
915
|
+
width: { type: "dxa", size: 9572 },
|
|
916
|
+
rows: node.rows.map((row, rowI) => new import_docx.TableRow({
|
|
917
|
+
tableHeader: rowI == 0,
|
|
918
|
+
cantSplit: true,
|
|
919
|
+
children: row.map((item, colI) => new import_docx.TableCell({
|
|
920
|
+
children: item.type != "text" ? renderNodeL2(item) : [
|
|
921
|
+
new import_docx.Paragraph({
|
|
922
|
+
children: renderText(item.text, node.normalFontSize ? void 0 : doc.table.text.size),
|
|
923
|
+
alignment: rowI == 0 ? doc.table.heading.align : node.align[colI] == "c" ? "center" : node.align[colI] == "r" ? "right" : "left",
|
|
924
|
+
indent: { firstLine: 0 },
|
|
925
|
+
spacing: { after: 0, line: 240 * doc.table.text.line_spacing }
|
|
926
|
+
})
|
|
927
|
+
]
|
|
928
|
+
}))
|
|
929
|
+
}))
|
|
930
|
+
})
|
|
931
|
+
];
|
|
932
|
+
case "tableOfContents":
|
|
933
|
+
return [
|
|
934
|
+
new import_docx.TableOfContents("\u041E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435", {
|
|
935
|
+
hyperlink: true,
|
|
936
|
+
headingStyleRange: "1-3"
|
|
937
|
+
}),
|
|
938
|
+
new import_docx.Paragraph({ children: [new import_docx.PageBreak()] })
|
|
939
|
+
];
|
|
940
|
+
case "image":
|
|
941
|
+
const type = node.src.split(".").at(-1) || "";
|
|
942
|
+
if (!["jpg", "png", "gif", "bmp", "svg"].includes(type))
|
|
943
|
+
throw new Error(`Unsupported image format: "${type}", file: ${node.src}`);
|
|
944
|
+
const img_path = getPath(node.src);
|
|
945
|
+
if (!fs3.existsSync(img_path))
|
|
946
|
+
throw new Error(`File not exist: ${node.src}`);
|
|
947
|
+
const data = fs3.readFileSync(img_path);
|
|
948
|
+
const dimensions = (0, import_image_size.imageSize)(data);
|
|
949
|
+
const [MaxW, MaxH] = [600, 800];
|
|
950
|
+
let [width, height] = [dimensions.width, dimensions.height];
|
|
951
|
+
if (node.width && node.height) [width, height] = [node.width, node.height];
|
|
952
|
+
if (node.width) [width, height] = [node.width, height / width * node.width];
|
|
953
|
+
if (node.height) [width, height] = [width / height * node.height, node.height];
|
|
954
|
+
if (height > MaxH) [width, height] = [width / height * MaxH, MaxH];
|
|
955
|
+
if (width > MaxW) [width, height] = [MaxW, height / width * MaxW];
|
|
956
|
+
return [
|
|
957
|
+
new import_docx.Paragraph({
|
|
958
|
+
alignment: "center",
|
|
959
|
+
indent: { firstLine: 0 },
|
|
960
|
+
spacing: {
|
|
961
|
+
line: 240,
|
|
962
|
+
...!node.text && doc.img.spacing.after !== void 0 ? { after: doc.img.spacing.after * 20 } : {},
|
|
963
|
+
...doc.img.spacing.before !== void 0 ? { before: doc.img.spacing.before * 20 } : {}
|
|
964
|
+
},
|
|
965
|
+
keepNext: !!node.text,
|
|
966
|
+
children: [
|
|
967
|
+
new import_docx.ImageRun({
|
|
968
|
+
type,
|
|
969
|
+
data,
|
|
970
|
+
transformation: { width, height },
|
|
971
|
+
...type == "svg" ? { fallback: { data: "", type: "png" } } : {}
|
|
972
|
+
})
|
|
973
|
+
]
|
|
974
|
+
}),
|
|
975
|
+
...node.text ? [
|
|
976
|
+
new import_docx.Paragraph({
|
|
977
|
+
children: renderText(node.text, doc.img.text.size),
|
|
978
|
+
alignment: "center",
|
|
979
|
+
indent: { firstLine: 0 },
|
|
980
|
+
spacing: {
|
|
981
|
+
line: 240,
|
|
982
|
+
...doc.img.spacing.after !== void 0 ? { after: doc.img.spacing.after * 20 } : {}
|
|
983
|
+
}
|
|
984
|
+
})
|
|
985
|
+
] : []
|
|
986
|
+
];
|
|
987
|
+
case "code":
|
|
988
|
+
const code = doc.code.highlight && renderCodeHighlighting(node.code, node.lang);
|
|
989
|
+
return [
|
|
990
|
+
...node.title ? [
|
|
991
|
+
new import_docx.Paragraph({
|
|
992
|
+
children: renderText(node.title, doc.code.title.size),
|
|
993
|
+
style: STYLE_code_title
|
|
994
|
+
})
|
|
995
|
+
] : prevNode?.type == "code" ? [
|
|
996
|
+
new import_docx.Paragraph({ spacing: { line: 20 } })
|
|
997
|
+
] : [],
|
|
998
|
+
...code ? code : node.code.split("\n").map((p, i) => new import_docx.Paragraph({
|
|
999
|
+
children: [new import_docx.TextRun(p)],
|
|
1000
|
+
style: STYLE_code,
|
|
1001
|
+
...i == 0 && !node.title && doc.code.spacing.before && prevNode?.type != "code" ? { spacing: { before: doc.code.spacing.before * 20 } } : {}
|
|
1002
|
+
}))
|
|
1003
|
+
];
|
|
1004
|
+
case "externalDoc":
|
|
1005
|
+
const doc_path = getPath(node.path);
|
|
1006
|
+
if (!fs3.existsSync(doc_path))
|
|
1007
|
+
throw new Error(`File not exist: ${node.path}`);
|
|
1008
|
+
const ext = import_path2.default.extname(doc_path);
|
|
1009
|
+
if (ext != ".docx" && ext != ".pdf")
|
|
1010
|
+
throw new Error(`File not .docx or .pdf: ${node.path}`);
|
|
1011
|
+
return new import_docx.Paragraph({
|
|
1012
|
+
text: `!!(${doc_path})${JSON.stringify(node.dict)}`,
|
|
1013
|
+
indent: { firstLine: 0 },
|
|
1014
|
+
alignment: "left"
|
|
1015
|
+
});
|
|
1016
|
+
case "sectionBreak":
|
|
1017
|
+
return [];
|
|
1018
|
+
default:
|
|
1019
|
+
node;
|
|
1020
|
+
throw new Error("switch default");
|
|
1021
|
+
}
|
|
1022
|
+
}, renderNodeL2 = function(node, prevChild, prevNode) {
|
|
1023
|
+
const r = renderNode2(node, prevChild, prevNode);
|
|
1024
|
+
if (r instanceof Array) return r;
|
|
1025
|
+
return [r];
|
|
1026
|
+
};
|
|
1027
|
+
var renderNode = renderNode2, renderNodeL = renderNodeL2;
|
|
1028
|
+
const children = [];
|
|
1029
|
+
sections.push({
|
|
1030
|
+
children,
|
|
1031
|
+
properties: {
|
|
1032
|
+
page: {
|
|
1033
|
+
pageNumbers: !section.pageStart ? {} : {
|
|
1034
|
+
start: section.pageStart
|
|
1035
|
+
},
|
|
1036
|
+
margin: {
|
|
1037
|
+
top: (0, import_docx.convertMillimetersToTwip)(20),
|
|
1038
|
+
left: (0, import_docx.convertMillimetersToTwip)(30),
|
|
1039
|
+
right: (0, import_docx.convertMillimetersToTwip)(15),
|
|
1040
|
+
bottom: (0, import_docx.convertMillimetersToTwip)(20)
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
footers: {
|
|
1045
|
+
default: new import_docx.Footer({
|
|
1046
|
+
children: [
|
|
1047
|
+
new import_docx.Paragraph({
|
|
1048
|
+
alignment: import_docx.AlignmentType.CENTER,
|
|
1049
|
+
children: [new import_docx.TextRun({
|
|
1050
|
+
children: section.pageStart ? [import_docx.PageNumber.CURRENT] : []
|
|
1051
|
+
})],
|
|
1052
|
+
indent: { firstLine: 0 },
|
|
1053
|
+
spacing: { line: 240 }
|
|
1054
|
+
})
|
|
1055
|
+
]
|
|
1056
|
+
})
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
for (let i = 0; i < section.nodes.length; i++)
|
|
1060
|
+
children.push(...renderNodeL2(section.nodes[i], children.at(-1), section.nodes[i - 1]));
|
|
1061
|
+
}
|
|
1062
|
+
const docx = new import_docx.Document({
|
|
1063
|
+
sections,
|
|
1064
|
+
externalStyles: genXml_style(assets, doc),
|
|
1065
|
+
// features: { updateFields: true },
|
|
1066
|
+
numbering: { config: numbering },
|
|
1067
|
+
...doc.rainbow ? { background: { color: "#000000" } } : {},
|
|
1068
|
+
...doc.hyphenation ? {
|
|
1069
|
+
hyphenation: {
|
|
1070
|
+
autoHyphenation: true,
|
|
1071
|
+
consecutiveHyphenLimit: 2,
|
|
1072
|
+
doNotHyphenateCaps: true,
|
|
1073
|
+
hyphenationZone: 360
|
|
1074
|
+
}
|
|
1075
|
+
} : {}
|
|
1076
|
+
// title: doc.title,
|
|
1077
|
+
// creator: doc.author,
|
|
1078
|
+
// lastModifiedBy: doc.author,
|
|
1079
|
+
});
|
|
1080
|
+
const buffer = await import_docx.Packer.toBuffer(docx, void 0, [
|
|
1081
|
+
{ path: "docProps/app.xml", data: genXml_app({ totalTime: doc.etime }) },
|
|
1082
|
+
{
|
|
1083
|
+
path: "docProps/core.xml",
|
|
1084
|
+
data: genXml_core({
|
|
1085
|
+
title: doc.title,
|
|
1086
|
+
creator: doc.author,
|
|
1087
|
+
createdAt: doc.ctime,
|
|
1088
|
+
modifiedAt: doc.mtime
|
|
1089
|
+
})
|
|
1090
|
+
}
|
|
1091
|
+
]);
|
|
1092
|
+
fs3.writeFileSync(fout, buffer);
|
|
1093
|
+
function renderText(text, size) {
|
|
1094
|
+
function renderRune(rune, link = false) {
|
|
1095
|
+
if (rune.anchor) return new import_docx.Bookmark({
|
|
1096
|
+
id: rune.anchor,
|
|
1097
|
+
children: [renderRune({ ...rune, anchor: void 0 })]
|
|
1098
|
+
});
|
|
1099
|
+
if (rune.link) {
|
|
1100
|
+
const children2 = [renderRune({ ...rune, link: void 0 }, true)];
|
|
1101
|
+
return rune.link.startsWith("#") ? new import_docx.InternalHyperlink({ children: children2, anchor: rune.link.slice(1) }) : new import_docx.ExternalHyperlink({ children: children2, link: rune.link });
|
|
1102
|
+
}
|
|
1103
|
+
let children = null;
|
|
1104
|
+
if (rune.type == "val" && rune.text == "pages") {
|
|
1105
|
+
rune.type = "text";
|
|
1106
|
+
children = [import_docx.PageNumber.TOTAL_PAGES];
|
|
1107
|
+
}
|
|
1108
|
+
return new import_docx.TextRun({
|
|
1109
|
+
...children ? { children } : { text: rune.text },
|
|
1110
|
+
language: { value: rune.lang == "en" ? "en-US" : "ru-RU" },
|
|
1111
|
+
...rune.linebreak ? { break: 1 } : {},
|
|
1112
|
+
...rune.bold ? { bold: true } : {},
|
|
1113
|
+
...rune.italic ? { italics: true } : {},
|
|
1114
|
+
...link ? { color: "0563c1", underline: { type: "single" } } : {},
|
|
1115
|
+
...rune.color ? { color: rune.color } : {},
|
|
1116
|
+
...size && size > 0 ? { size: size * 2 } : {},
|
|
1117
|
+
...rune.type && rune.type != "text" ? { highlight: "black", color: "ffffff" } : {},
|
|
1118
|
+
...rune.mono ? doc.backtickMono == "outline" ? { font: "consolas", size: (doc.text.size - 1) * 2, border: { style: "single", space: 2 } } : doc.backtickMono == "on" ? { font: "consolas", size: (doc.text.size - 1) * 2 } : doc.backtickMono == "italic" ? { italics: true } : {} : {}
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
if (typeof text == "string") text = [{ text }];
|
|
1122
|
+
if (text.at(-1)?.text == "" && text.at(-1)?.linebreak) text = text.slice(0, -1);
|
|
1123
|
+
text = splitRunesByLang(text);
|
|
1124
|
+
return text.map((r) => renderRune(r));
|
|
1125
|
+
function splitRunesByLang(runes) {
|
|
1126
|
+
const result = [];
|
|
1127
|
+
for (let r = 0; r < runes.length; r++) {
|
|
1128
|
+
const rune = runes[r];
|
|
1129
|
+
const text2 = rune.text;
|
|
1130
|
+
if (!text2 || text2.length === 0) {
|
|
1131
|
+
result.push(rune);
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
1134
|
+
let bufferStart = 0;
|
|
1135
|
+
let lastType = 0;
|
|
1136
|
+
let segmentType = 0;
|
|
1137
|
+
for (let i = 0; i < text2.length; i++) {
|
|
1138
|
+
const code = text2.charCodeAt(i);
|
|
1139
|
+
let type = 0;
|
|
1140
|
+
if (code >= 65 && code <= 90 || code >= 97 && code <= 122)
|
|
1141
|
+
type = 1;
|
|
1142
|
+
else if (code >= 1024 && code <= 1279)
|
|
1143
|
+
type = 2;
|
|
1144
|
+
if (segmentType === 0 && type !== 0) segmentType = type;
|
|
1145
|
+
if (i > bufferStart && type !== 0 && lastType !== 0 && type !== lastType) {
|
|
1146
|
+
result.push(copyRune(rune, text2.slice(bufferStart, i), segmentType, bufferStart == 0));
|
|
1147
|
+
bufferStart = i;
|
|
1148
|
+
segmentType = type;
|
|
1149
|
+
}
|
|
1150
|
+
if (type !== 0) lastType = type;
|
|
1151
|
+
}
|
|
1152
|
+
if (bufferStart === 0)
|
|
1153
|
+
result.push(copyRune(rune, text2, segmentType || lastType, true));
|
|
1154
|
+
else
|
|
1155
|
+
result.push(copyRune(rune, text2.slice(bufferStart), segmentType, false));
|
|
1156
|
+
}
|
|
1157
|
+
return result;
|
|
1158
|
+
function copyRune(src, text2, type, first) {
|
|
1159
|
+
return {
|
|
1160
|
+
...src,
|
|
1161
|
+
text: text2,
|
|
1162
|
+
anchor: first ? src.anchor : void 0,
|
|
1163
|
+
linebreak: src.linebreak && first,
|
|
1164
|
+
lang: type == 1 ? "en" : type == 2 ? "ru" : void 0
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
function addListItemLevel(levels, level, startIndex, itemCount, ordered, alternativeStyle, mark) {
|
|
1171
|
+
if (levels.find((v) => v.level == level)) return;
|
|
1172
|
+
levels.sort((a, b) => a.level - b.level);
|
|
1173
|
+
let indent = level;
|
|
1174
|
+
const format = ordered ? import_docx.LevelFormat.DECIMAL : import_docx.LevelFormat.BULLET;
|
|
1175
|
+
for (let i = 1; i < levels.length + 1; i++) {
|
|
1176
|
+
const prevprevformat = levels[i - 2]?.format;
|
|
1177
|
+
const prevformat = levels[i - 1]?.format;
|
|
1178
|
+
const curformat = i < levels.length ? levels[i]?.format : format;
|
|
1179
|
+
if (prevprevformat != curformat && prevformat != curformat) indent--;
|
|
1180
|
+
}
|
|
1181
|
+
const longList = startIndex + itemCount > 10;
|
|
1182
|
+
const left = alternativeStyle ? 0 : longList ? 20.5 : 17.5;
|
|
1183
|
+
const hanging = longList && !alternativeStyle ? (0, import_docx.convertMillimetersToTwip)(8) : null;
|
|
1184
|
+
const text = ordered ? alternativeStyle ? `%${level + 1}.` : mark == "." ? `%${level + 1}.` : `%${level + 1})` : (
|
|
1185
|
+
// mark == "*" ? "\u2022" : "\u2012";
|
|
1186
|
+
mark == "*" ? "\xB7" : "\u2012"
|
|
1187
|
+
);
|
|
1188
|
+
levels.push({
|
|
1189
|
+
level,
|
|
1190
|
+
format,
|
|
1191
|
+
start: startIndex,
|
|
1192
|
+
text,
|
|
1193
|
+
style: {
|
|
1194
|
+
...text == "\xB7" ? {
|
|
1195
|
+
run: {
|
|
1196
|
+
font: { name: "Symbol" }
|
|
1197
|
+
}
|
|
1198
|
+
} : {},
|
|
1199
|
+
paragraph: {
|
|
1200
|
+
indent: {
|
|
1201
|
+
left: (0, import_docx.convertMillimetersToTwip)(left + 5 * indent),
|
|
1202
|
+
...alternativeStyle ? { firstLine: (0, import_docx.convertMillimetersToTwip)(12.5) } : {},
|
|
1203
|
+
...hanging ? { hanging } : {}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
function renderCodeHighlighting(code, lang) {
|
|
1210
|
+
const grammar = import_prismjs.default.languages[lang.trim().toLowerCase()];
|
|
1211
|
+
if (!grammar) return null;
|
|
1212
|
+
const themeColors = {
|
|
1213
|
+
// shared
|
|
1214
|
+
"plain": "000000",
|
|
1215
|
+
"comment": "008000",
|
|
1216
|
+
"punctuation": "000000",
|
|
1217
|
+
"operator": "000000",
|
|
1218
|
+
// keywords & control flow
|
|
1219
|
+
"keyword": "0000ff",
|
|
1220
|
+
"boolean": "0000ff",
|
|
1221
|
+
"builtin": "0000ff",
|
|
1222
|
+
"important": "0000ff",
|
|
1223
|
+
// literals
|
|
1224
|
+
"string": lang === "css" ? "0451a5" : lang === "json" ? "a31515" : "a31515",
|
|
1225
|
+
"number": "098658",
|
|
1226
|
+
"constant": "0000ff",
|
|
1227
|
+
"symbol": "0000ff",
|
|
1228
|
+
"char": "a31515",
|
|
1229
|
+
// identifiers
|
|
1230
|
+
"class-name": lang === "js" || lang === "ts" ? "267f99" : "0451a5",
|
|
1231
|
+
"function": "0451a5",
|
|
1232
|
+
"variable": "000000",
|
|
1233
|
+
"namespace": "000000",
|
|
1234
|
+
"property": lang === "css" ? "e50000" : "0451a5",
|
|
1235
|
+
// markup / HTML / XML
|
|
1236
|
+
"tag": lang === "html" || lang === "xml" ? "800000" : "0000ff",
|
|
1237
|
+
"selector": "800000",
|
|
1238
|
+
"attr-name": "e50000",
|
|
1239
|
+
"attr-value": "a31515",
|
|
1240
|
+
"entity": "800000",
|
|
1241
|
+
"doctype": "808080",
|
|
1242
|
+
"cdata": "808080",
|
|
1243
|
+
"prolog": "808080",
|
|
1244
|
+
// CSS specific
|
|
1245
|
+
"atrule": "0000ff",
|
|
1246
|
+
"url": "0451a5",
|
|
1247
|
+
// regex
|
|
1248
|
+
"regex": "811f3f"
|
|
1249
|
+
};
|
|
1250
|
+
const tokens = import_prismjs.default.tokenize(code, grammar);
|
|
1251
|
+
return tokensToParagraphs(tokens);
|
|
1252
|
+
function tokensToParagraphs(tokens2) {
|
|
1253
|
+
const paragraphs = [];
|
|
1254
|
+
let currentRuns = [];
|
|
1255
|
+
function addText(text, type) {
|
|
1256
|
+
const lines = text.split("\n");
|
|
1257
|
+
lines.forEach((line, index) => {
|
|
1258
|
+
currentRuns.push(
|
|
1259
|
+
new import_docx.TextRun({
|
|
1260
|
+
text: line,
|
|
1261
|
+
color: themeColors[type] || themeColors["plain"],
|
|
1262
|
+
bold: type === "bold",
|
|
1263
|
+
italics: type === "italic"
|
|
1264
|
+
})
|
|
1265
|
+
);
|
|
1266
|
+
if (index < lines.length - 1) {
|
|
1267
|
+
paragraphs.push(new import_docx.Paragraph({ children: currentRuns, style: STYLE_code }));
|
|
1268
|
+
currentRuns = [];
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
function process2(token, parentType = "plain") {
|
|
1273
|
+
if (typeof token === "string")
|
|
1274
|
+
addText(token, parentType);
|
|
1275
|
+
else if (Array.isArray(token.content))
|
|
1276
|
+
token.content.forEach((t) => process2(t, token.type));
|
|
1277
|
+
else if (typeof token.content === "string")
|
|
1278
|
+
addText(token.content, token.type);
|
|
1279
|
+
else
|
|
1280
|
+
process2(token.content, token.type);
|
|
1281
|
+
}
|
|
1282
|
+
tokens2.forEach((t) => process2(t));
|
|
1283
|
+
if (currentRuns.length > 0) {
|
|
1284
|
+
paragraphs.push(new import_docx.Paragraph({ children: currentRuns, style: STYLE_code }));
|
|
1285
|
+
}
|
|
1286
|
+
return paragraphs;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
function genXml_app({ totalTime }) {
|
|
1290
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1291
|
+
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
|
|
1292
|
+
<TotalTime>${totalTime || randomInt(30, 120)}</TotalTime>
|
|
1293
|
+
</Properties>
|
|
1294
|
+
`;
|
|
1295
|
+
}
|
|
1296
|
+
function genXml_core({ title, creator, createdAt, modifiedAt }) {
|
|
1297
|
+
if (!createdAt) createdAt = /* @__PURE__ */ new Date();
|
|
1298
|
+
if (!modifiedAt) modifiedAt = /* @__PURE__ */ new Date();
|
|
1299
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1300
|
+
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
1301
|
+
<dc:title>${title || "Document"}</dc:title>
|
|
1302
|
+
<dc:creator>${creator || "Student"}</dc:creator>
|
|
1303
|
+
<cp:lastModifiedBy>${creator || "Student"}</cp:lastModifiedBy>
|
|
1304
|
+
<dcterms:created xsi:type="dcterms:W3CDTF">${createdAt.toISOString()}</dcterms:created>
|
|
1305
|
+
<dcterms:modified xsi:type="dcterms:W3CDTF">${modifiedAt.toISOString()}</dcterms:modified>
|
|
1306
|
+
</cp:coreProperties>`;
|
|
1307
|
+
}
|
|
1308
|
+
function genXml_style(assets, doc) {
|
|
1309
|
+
let xml = fs3.readFileSync(import_path2.default.join(assets, "styles.xml"), { encoding: "utf8" });
|
|
1310
|
+
xml = editStyle(`<w:style w:type="paragraph" w:default="1" w:styleId="a2">`, (xml2) => {
|
|
1311
|
+
xml2 = replaceTag(xml2, `<w:spacing w:line="${doc.text.line_spacing * 240}" w:lineRule="auto" w:after="${doc.text.spacing.after * 20}"/>`);
|
|
1312
|
+
xml2 = replaceTag(xml2, `<w:ind w:firstLine="${(0, import_docx.convertMillimetersToTwip)(doc.text.indent * 10)}"/>`);
|
|
1313
|
+
xml2 = replaceTag(xml2, `<w:sz w:val="${doc.text.size * 2}"/>`);
|
|
1314
|
+
return xml2;
|
|
1315
|
+
});
|
|
1316
|
+
xml = editStyle(`<w:style w:type="paragraph" w:customStyle="1" w:styleId="ListingCaption">`, (xml2) => {
|
|
1317
|
+
if (doc.code.spacing.before !== void 0)
|
|
1318
|
+
xml2 = replaceTag(xml2, `<w:spacing w:after="0" w:line="240" w:lineRule="auto" w:before="${doc.code.spacing.before * 20}"/>`);
|
|
1319
|
+
if (doc.code.title.style != "normal")
|
|
1320
|
+
xml2 = addrPrStyle(xml2, doc.code.title.style == "bold" ? "<w:b/>" : "<w:i/>");
|
|
1321
|
+
return xml2;
|
|
1322
|
+
});
|
|
1323
|
+
xml = editStyle(`<w:style w:type="paragraph" w:customStyle="1" w:styleId="ListingCode">`, (xml2) => {
|
|
1324
|
+
xml2 = replaceTag(xml2, `<w:sz w:val="${doc.code.text.size * 2}"/>`);
|
|
1325
|
+
if (doc.code.spacing.after !== void 0)
|
|
1326
|
+
xml2 = replaceTag(xml2, `<w:spacing w:line="240" w:lineRule="auto" w:after="${doc.code.spacing.after * 20}"/>`);
|
|
1327
|
+
return xml2;
|
|
1328
|
+
});
|
|
1329
|
+
xml = editStyle(`<w:style w:type="paragraph" w:customStyle="1" w:styleId="TableCaption">`, (xml2) => {
|
|
1330
|
+
if (doc.table.title.style != "normal")
|
|
1331
|
+
xml2 = addrPrStyle(xml2, doc.table.title.style == "bold" ? "<w:b/>" : "<w:i/>");
|
|
1332
|
+
return xml2;
|
|
1333
|
+
});
|
|
1334
|
+
return xml;
|
|
1335
|
+
function replaceTag(xml2, tag) {
|
|
1336
|
+
const tagName = /<([^\s]+)\b/.exec(tag)?.[1];
|
|
1337
|
+
if (!tagName) throw err();
|
|
1338
|
+
const regex = new RegExp(`(<${tagName}\\b[^>]*/>)`, "s");
|
|
1339
|
+
return xml2.replace(regex, tag);
|
|
1340
|
+
}
|
|
1341
|
+
function editStyle(tag, f) {
|
|
1342
|
+
const startI = xml.indexOf(tag);
|
|
1343
|
+
if (startI < 0) throw err();
|
|
1344
|
+
let endI = xml.indexOf(`</w:style>`, startI);
|
|
1345
|
+
if (endI < 0) throw err();
|
|
1346
|
+
endI += `</w:style>`.length;
|
|
1347
|
+
return xml.slice(0, startI) + f(xml.slice(startI, endI)) + xml.slice(endI);
|
|
1348
|
+
}
|
|
1349
|
+
function insertAfter(xml2, search, value) {
|
|
1350
|
+
const sI = xml2.indexOf(search);
|
|
1351
|
+
if (sI < 0) return { ok: false, xml: xml2 };
|
|
1352
|
+
const i = sI + search.length;
|
|
1353
|
+
return { ok: true, xml: xml2.slice(0, i) + value + xml2.slice(i) };
|
|
1354
|
+
}
|
|
1355
|
+
function insertBefore(xml2, search, value) {
|
|
1356
|
+
const i = xml2.indexOf(search);
|
|
1357
|
+
if (i < 0) return { ok: false, xml: xml2 };
|
|
1358
|
+
return { ok: true, xml: xml2.slice(0, i) + value + xml2.slice(i) };
|
|
1359
|
+
}
|
|
1360
|
+
function addrPrStyle(xml2, value) {
|
|
1361
|
+
let r = insertAfter(xml2, "<w:rPr>", value);
|
|
1362
|
+
if (r.ok) return r.xml;
|
|
1363
|
+
r = insertBefore(xml2, "</w:style>", `<w:rPr>${value}</w:rPr>`);
|
|
1364
|
+
if (r.ok) return r.xml;
|
|
1365
|
+
throw err();
|
|
1366
|
+
}
|
|
1367
|
+
function err() {
|
|
1368
|
+
return new Error(`styles.xml is corrupted (broken extension version - upgrade or downgrade)`);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// src/enricher.ts
|
|
1373
|
+
function enrichDoc(doc, logwarn = console.warn) {
|
|
1374
|
+
for (let i = 0; i < doc.nodes.length; i++) {
|
|
1375
|
+
const node = doc.nodes[i];
|
|
1376
|
+
if (node.type == "title" && node.text.toUpperCase().startsWith("\u0422\u0418\u0422\u0423\u041B\u042C\u041D\u0418\u041A")) {
|
|
1377
|
+
doc.nodes.splice(i, 1, { type: "text", text: node.text.toUpperCase() });
|
|
1378
|
+
doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
|
|
1379
|
+
i++;
|
|
1380
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u0420\u0415\u0424\u0415\u0420\u0410\u0422") {
|
|
1381
|
+
node.level = 0;
|
|
1382
|
+
node.text = node.text.toUpperCase();
|
|
1383
|
+
const nextNode = doc.nodes[i + 1];
|
|
1384
|
+
if (nextNode?.type == "text") {
|
|
1385
|
+
nextNode.noIndent = true;
|
|
1386
|
+
nextNode.text = trimEnd(nextNode.text, ".").toUpperCase();
|
|
1387
|
+
}
|
|
1388
|
+
doc.nodes.splice(i + 1, 0, { type: "text", tags: ["synopsis"], text: "\u041E\u0442\u0447\u0435\u0442 [!pages] \u0441., [!imgs] \u0440\u0438\u0441., [!tables] \u0442\u0430\u0431\u043B., [!codes] \u043B\u0438\u0441\u0442., [!sources] \u0438\u0441\u0442\u043E\u0447\u043D." });
|
|
1389
|
+
while (i + 1 < doc.nodes.length && doc.nodes[i + 1]?.type != "title") i++;
|
|
1390
|
+
doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
|
|
1391
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u041E\u0413\u041B\u0410\u0412\u041B\u0415\u041D\u0418\u0415") {
|
|
1392
|
+
node.level = 0;
|
|
1393
|
+
node.text = node.text.toUpperCase();
|
|
1394
|
+
doc.nodes.splice(i + 1, 0, { type: "tableOfContents" });
|
|
1395
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u0422\u0415\u0420\u041C\u0418\u041D\u042B \u0418 \u041E\u041F\u0420\u0415\u0414\u0415\u041B\u0415\u041D\u0418\u042F") {
|
|
1396
|
+
node.center = true;
|
|
1397
|
+
node.text = node.text.toUpperCase();
|
|
1398
|
+
const warn = () => logwarn("Wrong format of \u0422\u0415\u0420\u041C\u0418\u041D\u042B \u0418 \u041E\u041F\u0420\u0415\u0414\u0415\u041B\u0415\u041D\u0418\u042F");
|
|
1399
|
+
const list = doc.nodes[i + 1];
|
|
1400
|
+
if (list?.type != "list") {
|
|
1401
|
+
warn();
|
|
1402
|
+
continue;
|
|
1403
|
+
}
|
|
1404
|
+
const rows = [tableRow("\u0422\u0435\u0440\u043C\u0438\u043D", "\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435")];
|
|
1405
|
+
const align = ["l", "l"];
|
|
1406
|
+
for (const item of list.items) {
|
|
1407
|
+
if (item.type != "listItem") {
|
|
1408
|
+
warn();
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
const i2 = item.text.indexOf(":");
|
|
1412
|
+
if (i2 < 0) {
|
|
1413
|
+
warn();
|
|
1414
|
+
continue;
|
|
1415
|
+
}
|
|
1416
|
+
rows.push(tableRow(item.text.slice(0, i2).trim(), item.text.slice(i2 + 1).trim()));
|
|
1417
|
+
}
|
|
1418
|
+
doc.nodes.splice(i + 1, 1, { type: "text", text: "\u0412 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0435\u043C \u043E\u0442\u0447\u0435\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u044E\u0442\u0441\u044F \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u0442\u0435\u0440\u043C\u0438\u043D\u044B \u0441 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u043C\u0438 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u044F\u043C\u0438." });
|
|
1419
|
+
doc.nodes.splice(i + 2, 0, { type: "table", align, rows, normalFontSize: true, tags: ["definitions_table"] });
|
|
1420
|
+
doc.nodes.splice(i + 3, 0, { type: "pageBreak" });
|
|
1421
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u041F\u0415\u0420\u0415\u0427\u0415\u041D\u042C \u0421\u041E\u041A\u0420\u0410\u0429\u0415\u041D\u0418\u0419 \u0418 \u041E\u0411\u041E\u0417\u041D\u0410\u0427\u0415\u041D\u0418\u0419") {
|
|
1422
|
+
node.center = true;
|
|
1423
|
+
node.text = node.text.toUpperCase();
|
|
1424
|
+
const warn = () => logwarn("Wrong format of \u041F\u0415\u0420\u0415\u0427\u0415\u041D\u042C \u0421\u041E\u041A\u0420\u0410\u0429\u0415\u041D\u0418\u0419 \u0418 \u041E\u0411\u041E\u0417\u041D\u0410\u0427\u0415\u041D\u0418\u0419");
|
|
1425
|
+
const list = doc.nodes[i + 1];
|
|
1426
|
+
if (list?.type != "list") {
|
|
1427
|
+
warn();
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
const items = [];
|
|
1431
|
+
for (const item of list.items) {
|
|
1432
|
+
if (item.type != "listItem") {
|
|
1433
|
+
warn();
|
|
1434
|
+
continue;
|
|
1435
|
+
}
|
|
1436
|
+
items.push({ type: "text", text: trimEnd(item.text, "."), noIndent: true, noMargin: true });
|
|
1437
|
+
}
|
|
1438
|
+
doc.nodes.splice(i + 1, 1, { type: "text", text: "\u0412 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0435\u043C \u043E\u0442\u0447\u0435\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u044E\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u0441\u043E\u043A\u0440\u0430\u0449\u0435\u043D\u0438\u044F \u0438 \u043E\u0431\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F." });
|
|
1439
|
+
doc.nodes.splice(i + 2, 0, { type: "pageBreak" });
|
|
1440
|
+
doc.nodes.splice(i + 2, 0, ...items);
|
|
1441
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u0412\u0412\u0415\u0414\u0415\u041D\u0418\u0415") {
|
|
1442
|
+
node.center = true;
|
|
1443
|
+
node.text = node.text.toUpperCase();
|
|
1444
|
+
for (let j = i + 1; j < doc.nodes.length; j++) {
|
|
1445
|
+
const node2 = doc.nodes[j];
|
|
1446
|
+
if (node2?.type == "title") {
|
|
1447
|
+
doc.nodes.splice(j, 0, { type: "pageBreak" });
|
|
1448
|
+
break;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u0417\u0410\u041A\u041B\u042E\u0427\u0415\u041D\u0418\u0415") {
|
|
1452
|
+
node.center = true;
|
|
1453
|
+
node.text = node.text.toUpperCase();
|
|
1454
|
+
doc.nodes.splice(i, 0, { type: "pageBreak" });
|
|
1455
|
+
i++;
|
|
1456
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u0421\u041F\u0418\u0421\u041E\u041A \u0418\u0421\u041F\u041E\u041B\u042C\u0417\u041E\u0412\u0410\u041D\u041D\u042B\u0425 \u0418\u0421\u0422\u041E\u0427\u041D\u0418\u041A\u041E\u0412") {
|
|
1457
|
+
node.center = true;
|
|
1458
|
+
node.text = node.text.toUpperCase();
|
|
1459
|
+
doc.nodes.splice(i++, 0, { type: "pageBreak" });
|
|
1460
|
+
const nextNode = doc.nodes[i + 1];
|
|
1461
|
+
if (nextNode?.type == "list") {
|
|
1462
|
+
nextNode.alternativeStyle = true;
|
|
1463
|
+
i++;
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
const list = {
|
|
1467
|
+
type: "list",
|
|
1468
|
+
mark: ".",
|
|
1469
|
+
startIndex: 1,
|
|
1470
|
+
alternativeStyle: true,
|
|
1471
|
+
ordered: true,
|
|
1472
|
+
items: []
|
|
1473
|
+
};
|
|
1474
|
+
const startI = i + 1;
|
|
1475
|
+
while (true) {
|
|
1476
|
+
const textNode = doc.nodes[i + 1];
|
|
1477
|
+
if (textNode?.type != "text") break;
|
|
1478
|
+
const items = textNode.text.split(/\n\s*(?=\[[a-zA-Zа-яА-ЯёЁ_\d]+\])/);
|
|
1479
|
+
for (const item of items)
|
|
1480
|
+
list.items.push({ type: "listItem", text: item });
|
|
1481
|
+
i++;
|
|
1482
|
+
}
|
|
1483
|
+
if (list.items.length > 0)
|
|
1484
|
+
doc.nodes.splice(startI, i - startI + 1, list);
|
|
1485
|
+
} else if (node.type == "title" && node.text.toUpperCase() == "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u042F") {
|
|
1486
|
+
node.level = 0;
|
|
1487
|
+
node.center = true;
|
|
1488
|
+
node.text = node.text.toUpperCase();
|
|
1489
|
+
doc.nodes.splice(i++, 0, { type: "pageBreak" });
|
|
1490
|
+
for (let j = i + 1; j < doc.nodes.length; j++) {
|
|
1491
|
+
const node2 = doc.nodes[j];
|
|
1492
|
+
if (node2.type == "title") {
|
|
1493
|
+
doc.nodes.splice(i++ + 1, 0, { type: "text", text: "\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 " + node2.text.replace("]", "].") });
|
|
1494
|
+
j++;
|
|
1495
|
+
node2.level = 1;
|
|
1496
|
+
const splitI = node2.text.indexOf("]");
|
|
1497
|
+
doc.nodes.splice(j++, 0, { type: "pageBreak" });
|
|
1498
|
+
if (splitI >= 0) {
|
|
1499
|
+
doc.nodes.splice(j++ + 1, 0, { type: "text", text: node2.text.slice(splitI + 1), center: true });
|
|
1500
|
+
node2.text = "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u0415 " + node2.text.slice(0, splitI + 1);
|
|
1501
|
+
node2.center = true;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
} else if (node.type == "list") {
|
|
1506
|
+
let enrichList2 = function(list, isLastItem, isSubList = false) {
|
|
1507
|
+
const isLongList = 3 < Math.max(...list.items.filter((v) => v.type == "listItem").map((v) => v.text.split(/\s+/).length));
|
|
1508
|
+
const hasSublist = list.items.some((v) => v.type == "list");
|
|
1509
|
+
const ending = isLongList || hasSublist || isSubList ? ";" : ",";
|
|
1510
|
+
for (let i2 = 0; i2 < list.items.length; i2++) {
|
|
1511
|
+
const item = list.items[i2];
|
|
1512
|
+
const itemNext = list.items[i2 + 1];
|
|
1513
|
+
const isLast = i2 == list.items.length - 1;
|
|
1514
|
+
if (item.type == "list") enrichList2(item, isLast, true);
|
|
1515
|
+
else {
|
|
1516
|
+
const end = itemNext?.type == "list" ? ":" : isLastItem && isLast ? "." : ending;
|
|
1517
|
+
item.text = trimEnd(item.text, ".", ",", ";", ":", "!") + end;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
var enrichList = enrichList2;
|
|
1522
|
+
if (doc.list.autopunctuation) enrichList2(node, true);
|
|
1523
|
+
} else if (node.type == "image") {
|
|
1524
|
+
if (node.text)
|
|
1525
|
+
node.text = trimEnd(node.text, ".", ",", ";", ":", "!");
|
|
1526
|
+
} else if (node.type == "table") {
|
|
1527
|
+
if (node.title)
|
|
1528
|
+
node.title = trimEnd(node.title, ".", ",", ";", ":", "!");
|
|
1529
|
+
} else if (node.type == "code") {
|
|
1530
|
+
if (node.title)
|
|
1531
|
+
node.title = trimEnd(node.title, ".", ",", ";", ":", "!");
|
|
1532
|
+
} else if (node.type == "externalDoc") {
|
|
1533
|
+
const nextNode = doc.nodes[i + 1];
|
|
1534
|
+
if (nextNode && nextNode?.type != "externalDoc" && nextNode?.type != "pageBreak" && nextNode?.type != "sectionBreak") {
|
|
1535
|
+
doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
|
|
1536
|
+
}
|
|
1537
|
+
const prevNode = doc.nodes[i - 1];
|
|
1538
|
+
if (prevNode && prevNode?.type != "externalDoc" && prevNode?.type != "pageBreak" && prevNode?.type != "sectionBreak") {
|
|
1539
|
+
doc.nodes.splice(i, 0, { type: "pageBreak" });
|
|
1540
|
+
i++;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
// src/main.ts
|
|
1547
|
+
var import_child_process = require("child_process");
|
|
1548
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
1549
|
+
var import_fs = require("fs");
|
|
1550
|
+
var import_pdf_lib = require("pdf-lib");
|
|
1551
|
+
|
|
1552
|
+
// src/alchemist.ts
|
|
1553
|
+
var APPENDIX_NAME = "\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0418\u041A\u041B\u041C\u041D\u041F\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0428\u0429\u042D\u042E\u042F";
|
|
1554
|
+
function alchemist(doc, logwarn = console.warn) {
|
|
1555
|
+
const counter = {
|
|
1556
|
+
codesAll: 0,
|
|
1557
|
+
imgsAll: 0,
|
|
1558
|
+
tablesAll: 0,
|
|
1559
|
+
codes: 0,
|
|
1560
|
+
imgs: 0,
|
|
1561
|
+
tables: 0,
|
|
1562
|
+
titles: { l1: 0, l2: 0, l3: 0, l4: 0, l5: 0 }
|
|
1563
|
+
};
|
|
1564
|
+
const named = {};
|
|
1565
|
+
const vals = {};
|
|
1566
|
+
let lastRefI = 0;
|
|
1567
|
+
let prevNum = -1;
|
|
1568
|
+
let prevPrefix = "";
|
|
1569
|
+
let nextNum = -1;
|
|
1570
|
+
let nextPrefix = "";
|
|
1571
|
+
let prefix = "";
|
|
1572
|
+
let synopsis = null;
|
|
1573
|
+
let appendix = false;
|
|
1574
|
+
if (doc.numberingLazy) addLazyNumbering(doc);
|
|
1575
|
+
doc.nodes.forEach((node, i) => {
|
|
1576
|
+
if (nextNum < 0) {
|
|
1577
|
+
let l1 = counter.titles.l1;
|
|
1578
|
+
let codes = counter.codes;
|
|
1579
|
+
let imgs = counter.imgs;
|
|
1580
|
+
let tables = counter.tables;
|
|
1581
|
+
for (let j = i; j < doc.nodes.length && nextNum < 0; j++) {
|
|
1582
|
+
const n = doc.nodes[j];
|
|
1583
|
+
if (n.type == "code") nextNum = codes + 1;
|
|
1584
|
+
if (n.type == "image") nextNum = imgs + 1;
|
|
1585
|
+
if (n.type == "table") nextNum = tables + 1;
|
|
1586
|
+
if (n.type == "title" && n.level == 1 && doc.numberingSections) {
|
|
1587
|
+
const num = getTitleNum(n);
|
|
1588
|
+
if (num) l1 = num;
|
|
1589
|
+
else l1++;
|
|
1590
|
+
codes = 0;
|
|
1591
|
+
imgs = 0;
|
|
1592
|
+
tables = 0;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
nextPrefix = l1 > 0 && doc.numberingSections ? `${l1}.` : "";
|
|
1596
|
+
}
|
|
1597
|
+
if (node.tags && node.type == "text" && node.tags.includes("synopsis"))
|
|
1598
|
+
synopsis = node;
|
|
1599
|
+
if (node.type == "title") {
|
|
1600
|
+
for (let i2 = 1; i2 <= 5; i2++) {
|
|
1601
|
+
if (i2 == node.level) counter.titles[`l${i2}`]++;
|
|
1602
|
+
if (i2 > node.level) counter.titles[`l${i2}`] = 0;
|
|
1603
|
+
}
|
|
1604
|
+
if (node.level == 0 && node.text.map((r) => r.text).join("").trim().toUpperCase() == "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u042F") {
|
|
1605
|
+
appendix = true;
|
|
1606
|
+
counter.titles.l1 = 0;
|
|
1607
|
+
}
|
|
1608
|
+
if (node.level == 1) {
|
|
1609
|
+
const num = getTitleNum(node);
|
|
1610
|
+
if (num) counter.titles.l1 = num;
|
|
1611
|
+
if (doc.numberingSections || appendix) {
|
|
1612
|
+
counter.codes = 0;
|
|
1613
|
+
counter.imgs = 0;
|
|
1614
|
+
counter.tables = 0;
|
|
1615
|
+
}
|
|
1616
|
+
prefix = doc.numberingSections ? `${counter.titles.l1}.` : "";
|
|
1617
|
+
if (appendix) prefix = APPENDIX_NAME[counter.titles.l1 - 1] + ".";
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
materializeNode(node);
|
|
1621
|
+
if (node.type == "code" || node.type == "image" || node.type == "table") {
|
|
1622
|
+
if (node.type == "code") {
|
|
1623
|
+
counter.codes++;
|
|
1624
|
+
counter.codesAll++;
|
|
1625
|
+
}
|
|
1626
|
+
if (node.type == "image") {
|
|
1627
|
+
counter.imgs++;
|
|
1628
|
+
counter.imgsAll++;
|
|
1629
|
+
}
|
|
1630
|
+
if (node.type == "table" && !node.tags?.includes("definitions_table")) {
|
|
1631
|
+
counter.tables++;
|
|
1632
|
+
counter.tablesAll++;
|
|
1633
|
+
}
|
|
1634
|
+
prevNum = nextNum;
|
|
1635
|
+
prevPrefix = prefix;
|
|
1636
|
+
nextNum = -1;
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
const sourcesCount = crystallizeSources();
|
|
1640
|
+
vals["codes"]?.forEach((f) => f(counter.codes));
|
|
1641
|
+
vals["imgs"]?.forEach((f) => f(counter.imgs));
|
|
1642
|
+
vals["tables"]?.forEach((f) => f(counter.tables));
|
|
1643
|
+
vals["sources"]?.forEach((f) => f(sourcesCount));
|
|
1644
|
+
Object.entries(named).forEach(([k, v]) => {
|
|
1645
|
+
if (v instanceof Array) logwarn(`\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 [${k}]`);
|
|
1646
|
+
});
|
|
1647
|
+
if (synopsis) {
|
|
1648
|
+
synopsis.text = [
|
|
1649
|
+
"\u041E\u0442\u0447\u0435\u0442 ",
|
|
1650
|
+
"pages",
|
|
1651
|
+
" \u0441.",
|
|
1652
|
+
counter.imgsAll > 0 && `, ${counter.imgsAll} \u0440\u0438\u0441.`,
|
|
1653
|
+
counter.tablesAll > 0 && `, ${counter.tablesAll} \u0442\u0430\u0431\u043B.`,
|
|
1654
|
+
counter.codesAll > 0 && `, ${counter.codesAll} \u043B\u0438\u0441\u0442.`,
|
|
1655
|
+
sourcesCount > 0 && `, ${sourcesCount} \u0438\u0441\u0442\u043E\u0447\u043D.`,
|
|
1656
|
+
appendix && counter.titles.l1 > 0 && `, ${counter.titles.l1} \u043F\u0440\u0438\u043B.`
|
|
1657
|
+
].filter((v) => !!v).map((text, i) => ({ text, type: i == 1 ? "val" : "text" }));
|
|
1658
|
+
}
|
|
1659
|
+
function getTitleNum(node) {
|
|
1660
|
+
if (node.text.some((r) => r.type == "ref")) return null;
|
|
1661
|
+
const text = node.text[0]?.text;
|
|
1662
|
+
if (!text) return null;
|
|
1663
|
+
const m = /^\s*(\d+)/.exec(text);
|
|
1664
|
+
const num = parseInt(m?.[1] || "");
|
|
1665
|
+
if (!isFinite(num)) return null;
|
|
1666
|
+
return num;
|
|
1667
|
+
}
|
|
1668
|
+
function materializeNode(node) {
|
|
1669
|
+
if ("text" in node && node.text)
|
|
1670
|
+
materializeRunes(node.text, node);
|
|
1671
|
+
if ("title" in node && node.title)
|
|
1672
|
+
materializeRunes(node.title, node);
|
|
1673
|
+
if (node.type == "list") materializeList(node);
|
|
1674
|
+
if (node.type == "table") materializeTable(node);
|
|
1675
|
+
}
|
|
1676
|
+
function materializeList(node) {
|
|
1677
|
+
node.items.forEach((item) => {
|
|
1678
|
+
if (item.type == "list") materializeList(item);
|
|
1679
|
+
else materializeRunes(item.text, node);
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
function materializeTable(node) {
|
|
1683
|
+
node.rows.forEach((row) => row.forEach((item) => {
|
|
1684
|
+
materializeNode(item);
|
|
1685
|
+
}));
|
|
1686
|
+
}
|
|
1687
|
+
function materializeRunes(runes, node) {
|
|
1688
|
+
runes.forEach((rune, i) => {
|
|
1689
|
+
if (rune.type == "val") {
|
|
1690
|
+
if (!(rune.text in vals)) vals[rune.text] = [];
|
|
1691
|
+
vals[rune.text].push((n) => {
|
|
1692
|
+
rune.type = "text";
|
|
1693
|
+
rune.text = `${n}`;
|
|
1694
|
+
});
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
if (rune.type != "ref") return;
|
|
1698
|
+
const type = node.type;
|
|
1699
|
+
const m = /^(.*?)([-\+]\d+)?$/.exec(rune.text.replaceAll(/\s+/g, ""));
|
|
1700
|
+
const tag = m?.[1] || "";
|
|
1701
|
+
const math = m?.[2] || "";
|
|
1702
|
+
const mathSubstarct = math.at(0) == "-";
|
|
1703
|
+
const v = named[tag];
|
|
1704
|
+
const applyMath = (n) => {
|
|
1705
|
+
if (!math) return n;
|
|
1706
|
+
const v2 = parseInt(math.slice(1));
|
|
1707
|
+
if (mathSubstarct) return n - v2;
|
|
1708
|
+
return n + v2;
|
|
1709
|
+
};
|
|
1710
|
+
if (type == "title") {
|
|
1711
|
+
const num = counter.titles[`l${node.level}`];
|
|
1712
|
+
if (appendix) {
|
|
1713
|
+
const char = APPENDIX_NAME[counter.titles.l1 - 1];
|
|
1714
|
+
if (v instanceof Array) v.forEach((fn) => fn.f(-1, char));
|
|
1715
|
+
named[tag] = { n: -1, prefix: char };
|
|
1716
|
+
rune.type = "text";
|
|
1717
|
+
rune.text = char;
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const prefix2 = node.level <= 1 ? "" : repeat(node.level - 1, (i2) => counter.titles[`l${i2 + 1}`]).join(".") + ".";
|
|
1721
|
+
if (v instanceof Array) v.forEach((fn) => fn.f(num, prefix2));
|
|
1722
|
+
named[tag] = { n: num, prefix: prefix2 };
|
|
1723
|
+
rune.type = "text";
|
|
1724
|
+
rune.text = repeat(node.level, (i2) => counter.titles[`l${i2 + 1}`]).join(".");
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
if (type == "code" || type == "image" || type == "table") {
|
|
1728
|
+
let { num, text } = type == "code" ? { num: counter.codes, text: "\u041B\u0438\u0441\u0442\u0438\u043D\u0433" } : type == "image" ? { num: counter.imgs, text: "\u0420\u0438\u0441\u0443\u043D\u043E\u043A" } : type == "table" ? { num: counter.tables, text: "\u0422\u0430\u0431\u043B\u0438\u0446\u0430" } : (() => {
|
|
1729
|
+
throw new Error("switch default");
|
|
1730
|
+
})();
|
|
1731
|
+
num++;
|
|
1732
|
+
if (doc.numberingAutoprefix) {
|
|
1733
|
+
const prevRune = runes[i - 1];
|
|
1734
|
+
if (prevRune && prevRune.text.trim().toLowerCase() == text.toLowerCase())
|
|
1735
|
+
prevRune.text = "";
|
|
1736
|
+
const nextRune = runes[i + 1];
|
|
1737
|
+
if (nextRune) {
|
|
1738
|
+
nextRune.text = nextRune.text.trimStart();
|
|
1739
|
+
if (nextRune.text[0] == "-") nextRune.text = nextRune.text.slice(1);
|
|
1740
|
+
if (nextRune.text[0] == "\u2013") nextRune.text = nextRune.text.slice(1);
|
|
1741
|
+
nextRune.text = nextRune.text.trimStart();
|
|
1742
|
+
nextRune.text = toCapitalCase(nextRune.text);
|
|
1743
|
+
}
|
|
1744
|
+
text = `${text} ${prefix}${num} \u2013 `;
|
|
1745
|
+
} else text = `${prefix}${num}`;
|
|
1746
|
+
if (v instanceof Array) v.forEach((fn) => fn.f(num, prefix));
|
|
1747
|
+
else if (v && tag != "#") logwarn(`id [${tag}] ${type == "code" ? "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0430" : type == "image" ? "\u0440\u0438\u0441\u0443\u043D\u043A\u0430" : type == "table" ? "\u0442\u0430\u0431\u043B\u0438\u0446\u044B" : ""} \u0443\u0436\u0435 \u0437\u0430\u043D\u044F\u0442\u043E \u0447\u0435\u043C-\u0442\u043E \u0434\u0440\u0443\u0433\u0438\u043C`);
|
|
1748
|
+
named[tag] = { n: num, prefix };
|
|
1749
|
+
rune.type = "text";
|
|
1750
|
+
rune.text = text;
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
if (tag == "#") {
|
|
1754
|
+
if (nextNum < 0) return;
|
|
1755
|
+
rune.type = "text";
|
|
1756
|
+
if (mathSubstarct)
|
|
1757
|
+
rune.text = `${prevPrefix}${applyMath(prevNum + 1)}`;
|
|
1758
|
+
else
|
|
1759
|
+
rune.text = `${nextPrefix}${applyMath(nextNum)}`;
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
if (!v || v instanceof Array) {
|
|
1763
|
+
const f = (n, prefix2) => {
|
|
1764
|
+
rune.type = "text";
|
|
1765
|
+
rune.text = n < 0 ? prefix2 : `${prefix2}${applyMath(n)}`;
|
|
1766
|
+
};
|
|
1767
|
+
if (v) v.push({ f, i: lastRefI++ });
|
|
1768
|
+
else named[tag] = [{ f, i: lastRefI++ }];
|
|
1769
|
+
} else {
|
|
1770
|
+
rune.type = "text";
|
|
1771
|
+
rune.text = `${v.prefix}${applyMath(v.n)}`;
|
|
1772
|
+
}
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
function crystallizeSources() {
|
|
1776
|
+
const sourcesList = doc.nodes.find((node) => node.type == "list" && node.alternativeStyle);
|
|
1777
|
+
if (!sourcesList || sourcesList.type != "list") return 0;
|
|
1778
|
+
const items = sourcesList.items.filter((v) => v.type == "listItem").map((v) => v.text).map((item, i) => {
|
|
1779
|
+
const refI = item[0]?.text ? 0 : 1;
|
|
1780
|
+
const ref = item[refI];
|
|
1781
|
+
if (ref?.type != "ref") {
|
|
1782
|
+
return { text: item, ref: "", i: 99999 + i };
|
|
1783
|
+
}
|
|
1784
|
+
const refs = named[ref.text];
|
|
1785
|
+
if (refs && !(refs instanceof Array)) {
|
|
1786
|
+
logwarn(`id [${ref.text}] \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 \u0443\u0436\u0435 \u0437\u0430\u043D\u044F\u0442\u043E \u0447\u0435\u043C-\u0442\u043E \u0434\u0440\u0443\u0433\u0438\u043C`);
|
|
1787
|
+
return { text: item.slice(refI + 1), ref: "", i: 99999 + i };
|
|
1788
|
+
}
|
|
1789
|
+
const firstOccurrenceI = Math.min(...refs.map((v) => v.i));
|
|
1790
|
+
return { text: item.slice(refI + 1), ref: ref.text, i: firstOccurrenceI };
|
|
1791
|
+
});
|
|
1792
|
+
items.sort((a, b) => a.i - b.i);
|
|
1793
|
+
const hasIdAny = items.some((it) => !!it.ref);
|
|
1794
|
+
sourcesList.items = items.map((item, i) => {
|
|
1795
|
+
const key = hasIdAny ? item.ref : i + 1;
|
|
1796
|
+
const refs = named[key];
|
|
1797
|
+
named[key] = { prefix: "", n: i + 1 };
|
|
1798
|
+
if (refs instanceof Array) {
|
|
1799
|
+
if (hasIdAny && refs.length <= 1)
|
|
1800
|
+
logwarn(`\u0412 \u0442\u0435\u043A\u0441\u0442\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442 \u0441\u0441\u044B\u043B\u043A\u0438 \u043D\u0430 \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A: ${item.ref}`);
|
|
1801
|
+
refs.forEach((r) => hasIdAny ? r.f(i + 1, "") : r.f(-1, `[${i + 1}]`));
|
|
1802
|
+
}
|
|
1803
|
+
return { type: "listItem", text: item.text };
|
|
1804
|
+
});
|
|
1805
|
+
return sourcesList.items.length;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
function addLazyNumbering(doc) {
|
|
1809
|
+
doc.nodes.forEach((node) => {
|
|
1810
|
+
const runes = node.type == "code" || node.type == "table" ? node.title : node.type == "image" ? node.text : null;
|
|
1811
|
+
if (!runes) return;
|
|
1812
|
+
if (runes.find((rune) => rune.type == "ref")) return;
|
|
1813
|
+
runes.splice(0, 0, { text: "#", type: "ref" });
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
// src/main.ts
|
|
1818
|
+
var import_pizzip = __toESM(require("pizzip"));
|
|
1819
|
+
var DISABLE_MACRO = false;
|
|
1820
|
+
async function render({
|
|
1821
|
+
progress = (increment, message) => {
|
|
1822
|
+
},
|
|
1823
|
+
assets,
|
|
1824
|
+
file,
|
|
1825
|
+
output,
|
|
1826
|
+
renderPDF = false,
|
|
1827
|
+
removeIntermediateDocx = false,
|
|
1828
|
+
disableMacros = false,
|
|
1829
|
+
logwarn = console.warn,
|
|
1830
|
+
logPS = (msg) => console.log(`PS: ${msg}`),
|
|
1831
|
+
logPSError = (msg) => console.error(`PS: ${msg}`)
|
|
1832
|
+
}) {
|
|
1833
|
+
progress(10, "\u041F\u044B\u0442\u0430\u0435\u043C\u0441\u044F \u043F\u043E\u043D\u044F\u0442\u044C, \u0447\u0442\u043E \u0432\u044B \u0442\u0443\u0442 \u043D\u0430\u043F\u0438\u0441\u0430\u043B\u0438...");
|
|
1834
|
+
const fin = import_path3.default.resolve(file);
|
|
1835
|
+
const doc = await parseMD(fin, logwarn);
|
|
1836
|
+
progress(10, "\u041A\u043E\u043B\u0434\u0443\u0435\u043C \u043D\u0430\u0434 \u0441\u0438\u043D\u0442\u0430\u043A\u0441\u0438\u0441\u043E\u043C...");
|
|
1837
|
+
enrichDoc(doc, logwarn);
|
|
1838
|
+
const runicDoc = runifyDoc(doc);
|
|
1839
|
+
alchemist(runicDoc, logwarn);
|
|
1840
|
+
const pout = output && import_path3.default.parse(import_path3.default.resolve(output));
|
|
1841
|
+
if (pout) await import_promises3.default.mkdir(pout.dir, { recursive: true });
|
|
1842
|
+
const p = import_path3.default.parse(fin);
|
|
1843
|
+
const fdir = p.dir;
|
|
1844
|
+
const fname = trimEnd(p.name, ".g");
|
|
1845
|
+
const ftmp = import_path3.default.join(fdir, fname + ".tmp.docx");
|
|
1846
|
+
const fout = pout ? import_path3.default.join(pout.dir, pout.name + ".docx") : import_path3.default.join(fdir, fname + ".docx");
|
|
1847
|
+
if (await checkIfFileIsBlocked(ftmp))
|
|
1848
|
+
throw new Error(`\u0417\u0430\u043A\u0440\u043E\u0439\u0442\u0435 docx \u0444\u0430\u0439\u043B. Output file is busy or locked: ${ftmp}`);
|
|
1849
|
+
if (await checkIfFileIsBlocked(fout))
|
|
1850
|
+
throw new Error(`\u0417\u0430\u043A\u0440\u043E\u0439\u0442\u0435 docx \u0444\u0430\u0439\u043B. Output file is busy or locked: ${fout}`);
|
|
1851
|
+
progress(10, phrase_renderDocx());
|
|
1852
|
+
await serializeDocx(runicDoc, ftmp, fdir, assets);
|
|
1853
|
+
let willRunMacros = !disableMacros && (renderPDF || hasReasonForRunningMacros(runicDoc));
|
|
1854
|
+
let limitedRender = false;
|
|
1855
|
+
if (process.platform != "win32" && willRunMacros) {
|
|
1856
|
+
limitedRender = true;
|
|
1857
|
+
willRunMacros = false;
|
|
1858
|
+
}
|
|
1859
|
+
if (willRunMacros) {
|
|
1860
|
+
progress(20, phrase_runMacros());
|
|
1861
|
+
const tmpfolder = import_path3.default.join(pout ? pout.dir : fdir, ".md2gost_out");
|
|
1862
|
+
await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
|
|
1863
|
+
try {
|
|
1864
|
+
const ok = await runDocxMacro(progress, logPS, logPSError, assets, fdir, ftmp, fout, renderPDF);
|
|
1865
|
+
if (!ok) {
|
|
1866
|
+
await import_promises3.default.rename(ftmp, fout);
|
|
1867
|
+
return { fout, err: "inPS" };
|
|
1868
|
+
}
|
|
1869
|
+
} catch (x) {
|
|
1870
|
+
await import_promises3.default.rename(ftmp, fout);
|
|
1871
|
+
return { fout, err: "noPS", errS: x };
|
|
1872
|
+
}
|
|
1873
|
+
await import_promises3.default.unlink(ftmp);
|
|
1874
|
+
const errorTxt = import_path3.default.join(tmpfolder, "error.txt");
|
|
1875
|
+
if ((0, import_fs.existsSync)(errorTxt)) {
|
|
1876
|
+
const err = await import_promises3.default.readFile(errorTxt);
|
|
1877
|
+
await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
|
|
1878
|
+
return { fout, err: "vba", errS: `${err}` };
|
|
1879
|
+
}
|
|
1880
|
+
await updateMetadata(fout, doc);
|
|
1881
|
+
if (renderPDF) {
|
|
1882
|
+
progress(10, phrase_combine());
|
|
1883
|
+
if (!(0, import_fs.existsSync)(tmpfolder))
|
|
1884
|
+
return { fout, err: "pdf" };
|
|
1885
|
+
try {
|
|
1886
|
+
const files = (await import_promises3.default.readdir(tmpfolder)).sort().map((f) => import_path3.default.join(tmpfolder, f));
|
|
1887
|
+
const pdf = pout ? import_path3.default.join(pout.dir, pout.base) : import_path3.default.join(fdir, fname + ".pdf");
|
|
1888
|
+
await mergePDFs(files, pdf, doc);
|
|
1889
|
+
await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
|
|
1890
|
+
if (removeIntermediateDocx && (0, import_fs.existsSync)(fout)) await import_promises3.default.unlink(fout);
|
|
1891
|
+
return { fout: pdf };
|
|
1892
|
+
} catch (err) {
|
|
1893
|
+
return { fout, err: "pdf", errS: err };
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
} else {
|
|
1897
|
+
await import_promises3.default.rename(ftmp, fout);
|
|
1898
|
+
}
|
|
1899
|
+
return { fout, err: limitedRender ? "noWin" : void 0 };
|
|
1900
|
+
}
|
|
1901
|
+
function hasReasonForRunningMacros(doc) {
|
|
1902
|
+
if (DISABLE_MACRO) return false;
|
|
1903
|
+
return doc.nodes.some((n) => n.type == "code" || n.type == "table");
|
|
1904
|
+
}
|
|
1905
|
+
function runDocxMacro(progress, log, logError, assets, cwd, fin, fout, renderPDF) {
|
|
1906
|
+
const script = import_path3.default.join(assets, "run.ps1");
|
|
1907
|
+
const templateMacro = import_path3.default.join(assets, "template.dotm");
|
|
1908
|
+
return new Promise((res, rej) => {
|
|
1909
|
+
const child = (0, import_child_process.spawn)("powershell", [
|
|
1910
|
+
"-NoProfile",
|
|
1911
|
+
"-ExecutionPolicy",
|
|
1912
|
+
"Bypass",
|
|
1913
|
+
"-File",
|
|
1914
|
+
script,
|
|
1915
|
+
"-InputDoc",
|
|
1916
|
+
fin,
|
|
1917
|
+
"-OutputDoc",
|
|
1918
|
+
fout,
|
|
1919
|
+
"-MacroTemplate",
|
|
1920
|
+
templateMacro,
|
|
1921
|
+
...renderPDF ? ["-RenderPDF"] : []
|
|
1922
|
+
], { cwd });
|
|
1923
|
+
child.stdout.on("data", (data) => {
|
|
1924
|
+
data = `${data}`;
|
|
1925
|
+
const m = /\[\*(\d)\]/.exec(data);
|
|
1926
|
+
if (m) progress(12, {
|
|
1927
|
+
// "1": "Fixing breaks (listings)",
|
|
1928
|
+
"1": render_fixingBreaks(),
|
|
1929
|
+
// "2": "Fixing breaks (tables)",
|
|
1930
|
+
"2": render_fixingBreaks(),
|
|
1931
|
+
// "3": "Rendering to PDF",
|
|
1932
|
+
"3": render_renderPDF()
|
|
1933
|
+
}[m[1]] || "Make some work");
|
|
1934
|
+
log(data);
|
|
1935
|
+
});
|
|
1936
|
+
let ok = true;
|
|
1937
|
+
child.stderr.on("data", (data) => {
|
|
1938
|
+
ok = false;
|
|
1939
|
+
logError(`${data}`);
|
|
1940
|
+
});
|
|
1941
|
+
child.on("close", () => res(ok));
|
|
1942
|
+
child.on("error", rej);
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
async function mergePDFs(files, fout, doc) {
|
|
1946
|
+
const mergedPdf = await import_pdf_lib.PDFDocument.create();
|
|
1947
|
+
if (doc?.title) mergedPdf.setTitle(doc.title, { showInWindowTitleBar: true });
|
|
1948
|
+
if (doc?.author) mergedPdf.setAuthor(doc.author);
|
|
1949
|
+
if (doc?.ctime) mergedPdf.setCreationDate(doc.ctime);
|
|
1950
|
+
if (doc?.mtime) mergedPdf.setModificationDate(doc.mtime);
|
|
1951
|
+
for (const file of files) {
|
|
1952
|
+
const bytes = await import_promises3.default.readFile(file);
|
|
1953
|
+
const pdf = await import_pdf_lib.PDFDocument.load(bytes);
|
|
1954
|
+
const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
|
|
1955
|
+
pages.forEach((page) => mergedPdf.addPage(page));
|
|
1956
|
+
}
|
|
1957
|
+
const pdfBytes = await mergedPdf.save();
|
|
1958
|
+
await import_promises3.default.writeFile(fout, pdfBytes);
|
|
1959
|
+
}
|
|
1960
|
+
async function updateMetadata(docfile, doc) {
|
|
1961
|
+
const content = await import_promises3.default.readFile(docfile);
|
|
1962
|
+
const zip = new import_pizzip.default(content);
|
|
1963
|
+
function replaceTag(xml, tag, value) {
|
|
1964
|
+
const regex = new RegExp(`(<${tag}\\b[^>]*>)(.*?)(</${tag}>)`, "gs");
|
|
1965
|
+
return xml.replace(
|
|
1966
|
+
regex,
|
|
1967
|
+
(m, otag, old, ctag) => `${otag}${escapeXml(value)}${ctag}`
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
let coreXml = zip.file("docProps/core.xml").asText();
|
|
1971
|
+
coreXml = replaceTag(coreXml, "dc:title", doc.title || "Document");
|
|
1972
|
+
if (doc.ctime) coreXml = replaceTag(coreXml, "dcterms:created", doc.ctime.toISOString());
|
|
1973
|
+
if (doc.mtime) coreXml = replaceTag(coreXml, "dcterms:modified", doc.mtime.toISOString());
|
|
1974
|
+
coreXml = replaceTag(coreXml, "dc:creator", doc.author || "Student");
|
|
1975
|
+
coreXml = replaceTag(coreXml, "cp:lastModifiedBy", doc.author || "Student");
|
|
1976
|
+
zip.file("docProps/core.xml", coreXml);
|
|
1977
|
+
let appXml = zip.file("docProps/app.xml").asText();
|
|
1978
|
+
appXml = replaceTag(appXml, "TotalTime", `${doc.etime || randomInt(30, 120)}`);
|
|
1979
|
+
zip.file("docProps/app.xml", appXml);
|
|
1980
|
+
const buffer = zip.generate({ type: "nodebuffer" });
|
|
1981
|
+
await import_promises3.default.writeFile(docfile, buffer);
|
|
1982
|
+
function escapeXml(unsafe) {
|
|
1983
|
+
return unsafe.replaceAll(/[<>&"']/g, (ch) => {
|
|
1984
|
+
switch (ch) {
|
|
1985
|
+
case "<":
|
|
1986
|
+
return "<";
|
|
1987
|
+
case ">":
|
|
1988
|
+
return ">";
|
|
1989
|
+
case "&":
|
|
1990
|
+
return "&";
|
|
1991
|
+
case '"':
|
|
1992
|
+
return """;
|
|
1993
|
+
case "'":
|
|
1994
|
+
return "'";
|
|
1995
|
+
default:
|
|
1996
|
+
return ch;
|
|
1997
|
+
}
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
var phrase_renderDocx = () => choice(
|
|
2002
|
+
"\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u0443\u0435\u043C \u0431\u0443\u043C\u0430\u0436\u043D\u044B\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043A\u0442...",
|
|
2003
|
+
"\u041A\u0443\u0435\u043C DOCX \u0432 \u0442\u0435\u043A\u0441\u0442\u043E\u0432\u043E\u0439 \u043A\u0443\u0437\u043D\u0438\u0446\u0435...",
|
|
2004
|
+
"\u041F\u043B\u0435\u0442\u0435\u043C \u043F\u043E\u043B\u043E\u0442\u043D\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430...",
|
|
2005
|
+
"\u0422\u0440\u0430\u043D\u0441\u043C\u0443\u0442\u0438\u0440\u0443\u0435\u043C \u043F\u0440\u043E\u0441\u0442\u044B\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u0432 \u0432\u0435\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B...",
|
|
2006
|
+
"\u0412\u044B\u043A\u043E\u0432\u044B\u0432\u0430\u0435\u043C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0438\u0437 \u0440\u0443\u0434\u044B \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432...",
|
|
2007
|
+
"\u041E\u0442\u043B\u0438\u0432\u0430\u0435\u043C \u0444\u043E\u0440\u043C\u0443 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0440\u0430\u043D\u0438\u0446...",
|
|
2008
|
+
"\u0417\u0430\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u0435\u043C \u0444\u0443\u043D\u0434\u0430\u043C\u0435\u043D\u0442 \u0432\u0435\u043B\u0438\u043A\u043E\u0433\u043E \u0442\u0440\u0430\u043A\u0442\u0430\u0442\u0430...",
|
|
2009
|
+
"\u041F\u0435\u0440\u0435\u043F\u043B\u0430\u0432\u043B\u044F\u0435\u043C \u043C\u044B\u0441\u043B\u0438 \u0432 \u0441\u0442\u0440\u043E\u0439\u043D\u044B\u0435 \u0430\u0431\u0437\u0430\u0446\u044B...",
|
|
2010
|
+
"\u0421\u043B\u0430\u0433\u0430\u0435\u043C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0432 \u0433\u0430\u0440\u043C\u043E\u043D\u0438\u044E \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B..."
|
|
2011
|
+
);
|
|
2012
|
+
var phrase_runMacros = () => choice(
|
|
2013
|
+
"\u041F\u0440\u043E\u0431\u0443\u0436\u0434\u0430\u0435\u043C \u0434\u0440\u0435\u0432\u043D\u0438\u0445 \u0434\u0443\u0445\u043E\u0432 VBA...",
|
|
2014
|
+
"\u041F\u0440\u0438\u0437\u044B\u0432\u0430\u0435\u043C \u0434\u0443\u0445 \u0412\u043E\u0440\u0434\u0430 \u0438\u0437 \u0431\u0435\u0437\u0434\u043D\u044B \u043E\u0444\u0438\u0441\u043D\u043E\u0433\u043E \u043F\u0430\u043A\u0435\u0442\u0430...",
|
|
2015
|
+
"\u0412\u0434\u044B\u0445\u0430\u0435\u043C \u043C\u0430\u043D\u0443 \u0432 \u0441\u043F\u044F\u0449\u0438\u0435 \u0440\u0443\u043D\u044B \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438...",
|
|
2016
|
+
"\u041E\u0442\u043F\u0438\u0440\u0430\u0435\u043C \u0442\u0430\u0439\u043D\u044B\u0435 \u0444\u0443\u043D\u043A\u0446\u0438\u0438 \u043E\u0444\u0438\u0441\u043D\u043E\u0439 \u043C\u0430\u0433\u0438\u0438..."
|
|
2017
|
+
);
|
|
2018
|
+
var render_fixingBreaks = () => choice(
|
|
2019
|
+
'\u041F\u043E\u0434\u043A\u043B\u0435\u0438\u0432\u0430\u0435\u043C "\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435 \u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0430" \u043D\u0430 \u0440\u0430\u0437\u043E\u0440\u0432\u0430\u043D\u043D\u044B\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B...',
|
|
2020
|
+
'\u041F\u043E\u0434\u043A\u043B\u0435\u0438\u0432\u0430\u0435\u043C "\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435 \u0442\u0430\u0431\u043B\u0438\u0446\u044B" \u043D\u0430 \u0440\u0430\u0437\u043E\u0440\u0432\u0430\u043D\u043D\u044B\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B...',
|
|
2021
|
+
"\u0423\u043A\u0440\u0435\u043F\u043B\u044F\u0435\u043C \u0441\u0442\u0435\u043D\u044B \u0441\u0435\u043A\u0446\u0438\u0439 \u0441\u0432\u044F\u0437\u0443\u044E\u0449\u0438\u043C\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438...",
|
|
2022
|
+
"\u041D\u0430\u043D\u043E\u0441\u0438\u043C \u0440\u0443\u043D\u044B \u043F\u0440\u0435\u0435\u043C\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0441\u0442\u0438 \u043D\u0430 \u0440\u0430\u0437\u0440\u044B\u0432\u044B \u0441\u0442\u0440\u0430\u043D\u0438\u0446...",
|
|
2023
|
+
"\u0427\u0438\u043D\u0438\u043C \u0431\u0430\u0433 \u0440\u0430\u0437\u0440\u044B\u0432\u0430 \u043F\u043E\u0432\u0435\u0441\u0442\u0432\u043E\u0432\u0430\u043D\u0438\u044F...",
|
|
2024
|
+
"\u0421\u043E\u0435\u0434\u0438\u043D\u044F\u0435\u043C \u043E\u0441\u043A\u043E\u043B\u043A\u0438 \u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0430 \u0432 \u0435\u0434\u0438\u043D\u043E\u0435 \u043F\u043E\u043B\u043E\u0442\u043D\u043E...",
|
|
2025
|
+
"\u041D\u0430\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u0435\u043C \u0447\u0430\u0440\u044B \u043D\u0435\u043F\u0440\u0435\u0440\u044B\u0432\u043D\u043E\u0441\u0442\u0438 \u043D\u0430 \u0442\u0435\u043A\u0441\u0442..."
|
|
2026
|
+
);
|
|
2027
|
+
var render_renderPDF = () => choice(
|
|
2028
|
+
"\u0421\u043E\u0431\u0438\u0440\u0430\u0435\u043C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u0438 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043C \u0438\u0445 \u0432 PDF-\u0441\u0432\u0438\u0442\u043A\u0438...",
|
|
2029
|
+
"\u041E\u0431\u0440\u0430\u0449\u0430\u0435\u043C \u0436\u0438\u0432\u043E\u0435 \u0441\u043B\u043E\u0432\u043E \u0432 \u043D\u0435\u0437\u044B\u0431\u043B\u0435\u043C\u044B\u0439 \u043A\u0430\u043C\u0435\u043D\u044C PDF...",
|
|
2030
|
+
"\u041D\u0430\u0432\u0435\u043A\u0438 \u0437\u0430\u043F\u0435\u0447\u0430\u0442\u043B\u0435\u0432\u0430\u0435\u043C \u0441\u0432\u0438\u0442\u043A\u0438 \u0432 \u043A\u0440\u0438\u0441\u0442\u0430\u043B\u043B\u0430\u0445 \u043F\u0430\u043C\u044F\u0442\u0438...",
|
|
2031
|
+
"\u0417\u0430\u043F\u0435\u0447\u0430\u0442\u044B\u0432\u0430\u0435\u043C \u0442\u0435\u043A\u0441\u0442 \u0432 \u044F\u043D\u0442\u0430\u0440\u0435 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 PDF..."
|
|
2032
|
+
);
|
|
2033
|
+
var phrase_combine = () => choice(
|
|
2034
|
+
"\u0421\u043A\u043B\u0435\u0438\u0432\u0430\u0435\u043C \u0432\u0441\u0451 \u0441\u0438\u043D\u0435\u0439 \u0438\u0437\u043E\u043B\u0435\u043D\u0442\u043E\u0439...",
|
|
2035
|
+
"\u0421\u043A\u0440\u0435\u043F\u043B\u044F\u0435\u043C \u043F\u0435\u0447\u0430\u0442\u044F\u043C\u0438 \u0441\u0443\u0434\u044C\u0431\u044B \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044E\u044E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443...",
|
|
2036
|
+
"\u0421\u043F\u043B\u0430\u0432\u043B\u044F\u0435\u043C \u0444\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043A\u0442 \u0438\u0437 \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u0430 \u043E\u0441\u043A\u043E\u043B\u043A\u043E\u0432..."
|
|
2037
|
+
);
|
|
2038
|
+
|
|
2039
|
+
// src/index.ts
|
|
2040
|
+
var import_assert = __toESM(require("assert"));
|
|
2041
|
+
async function renderMarkdown(config) {
|
|
2042
|
+
(0, import_assert.default)(config && typeof config == "object", "Config object is required");
|
|
2043
|
+
(0, import_assert.default)(typeof config.input == "string", "Input file path must be a string.");
|
|
2044
|
+
(0, import_assert.default)(typeof config.output == "string" || typeof config.output == "undefined", "Output path must be a string or undefined.");
|
|
2045
|
+
(0, import_assert.default)(config.format == "docx" || config.format == "pdf" || typeof config.format == "undefined", "Format must be either 'docx' or 'pdf', or undefined.");
|
|
2046
|
+
(0, import_assert.default)(typeof config.keepIntermediateDocx == "boolean" || typeof config.keepIntermediateDocx == "undefined", "keepIntermediateDocx must be a boolean or undefined.");
|
|
2047
|
+
(0, import_assert.default)(typeof config.disableMacros == "boolean" || typeof config.disableMacros == "undefined", "disableMacros must be a boolean or undefined.");
|
|
2048
|
+
(0, import_assert.default)(typeof config.progress == "function" || typeof config.progress == "undefined", "Progress callback must be a function or undefined.");
|
|
2049
|
+
{
|
|
2050
|
+
const extraProps = getExtraProperties(
|
|
2051
|
+
config,
|
|
2052
|
+
["input", "output", "format", "keepIntermediateDocx", "disableMacros", "progress"]
|
|
2053
|
+
);
|
|
2054
|
+
(0, import_assert.default)(extraProps.length == 0, `Found unknown properties in config: ${extraProps.join(", ")}`);
|
|
2055
|
+
}
|
|
2056
|
+
const renderPDF = config.format === "pdf" || !config.format && !!config.output?.endsWith(".pdf");
|
|
2057
|
+
const removeIntermediateDocx = !config.keepIntermediateDocx;
|
|
2058
|
+
const disableMacros = !!config.disableMacros;
|
|
2059
|
+
const warnings = [];
|
|
2060
|
+
const logPS = [];
|
|
2061
|
+
let totalPercent = 0;
|
|
2062
|
+
const handleProgress = config.progress ? (increment, message) => {
|
|
2063
|
+
totalPercent = Math.min(totalPercent + increment, 99);
|
|
2064
|
+
config.progress(totalPercent, message);
|
|
2065
|
+
} : void 0;
|
|
2066
|
+
try {
|
|
2067
|
+
let throwMDE2 = function(code, msg) {
|
|
2068
|
+
throw new MDRenderError(code, msg, fout, warnings, logPS, errS ? { cause: errS } : void 0);
|
|
2069
|
+
};
|
|
2070
|
+
var throwMDE = throwMDE2;
|
|
2071
|
+
const { fout, err, errS } = await render({
|
|
2072
|
+
progress: handleProgress,
|
|
2073
|
+
assets: getAssetsDir(),
|
|
2074
|
+
file: config.input,
|
|
2075
|
+
output: config.output,
|
|
2076
|
+
renderPDF,
|
|
2077
|
+
removeIntermediateDocx,
|
|
2078
|
+
disableMacros,
|
|
2079
|
+
logwarn: (msg) => warnings.push(msg),
|
|
2080
|
+
logPS: (msg) => logPS.push(msg),
|
|
2081
|
+
logPSError: (msg) => logPS.push(msg)
|
|
2082
|
+
});
|
|
2083
|
+
config.progress?.(100, "Done!");
|
|
2084
|
+
;
|
|
2085
|
+
if (err == "noPS") throwMDE2("noPS", `Failed to initialize PowerShell. Ensure PowerShell is installed and explicitly added to your system's PATH environment variable.`);
|
|
2086
|
+
if (err == "inPS") throwMDE2("inPS", `An unexpected error occurred executing commands inside PowerShell. Verify that Microsoft Word is properly installed and licensed.`);
|
|
2087
|
+
if (err == "vba") throwMDE2("vba", `Microsoft Word VBA Macro execution failed: ${errS}`);
|
|
2088
|
+
if (err == "pdf") throwMDE2("pdf", `Failed to export document to PDF.`);
|
|
2089
|
+
if (err == "noWin") throwMDE2("noWin", `Platform restriction: Extended formatting macros and PDF rendering are only supported natively on Windows systems.`);
|
|
2090
|
+
let intermediateDocxPath;
|
|
2091
|
+
if (renderPDF) {
|
|
2092
|
+
const pin = import_path4.default.parse(import_path4.default.resolve(config.input));
|
|
2093
|
+
const fname = pin.name.endsWith(".g") ? pin.name.slice(0, -2) : pin.name;
|
|
2094
|
+
const pout = config.output ? import_path4.default.parse(import_path4.default.resolve(config.output)) : void 0;
|
|
2095
|
+
intermediateDocxPath = pout ? import_path4.default.join(pout.dir, pout.name + ".docx") : import_path4.default.join(pin.dir, fname + ".docx");
|
|
2096
|
+
}
|
|
2097
|
+
return {
|
|
2098
|
+
filePath: fout,
|
|
2099
|
+
...intermediateDocxPath && { intermediateDocxPath },
|
|
2100
|
+
warnings
|
|
2101
|
+
};
|
|
2102
|
+
} catch (x) {
|
|
2103
|
+
if (x instanceof MDRenderError) throw x;
|
|
2104
|
+
const message = x instanceof Error ? x.message : String(x);
|
|
2105
|
+
throw new MDRenderError("unknown", `An unhandled internal error occurred during rendering: ${message}`, null, warnings, logPS, { cause: x });
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
var MDRenderError = class _MDRenderError extends Error {
|
|
2109
|
+
/**
|
|
2110
|
+
* File path of the partially rendered `.docx` file, if available when the error occurred.
|
|
2111
|
+
*/
|
|
2112
|
+
renderedFile;
|
|
2113
|
+
/**
|
|
2114
|
+
* Code indicating the underlying cause of the failure:
|
|
2115
|
+
* - `unknown`: An unhandled or unexpected internal runtime error.
|
|
2116
|
+
* - `noPS`: PowerShell could not be started or found in the system PATH.
|
|
2117
|
+
* - `inPS`: A failure occurred inside PowerShell; MS Word may be missing or corrupt.
|
|
2118
|
+
* - `vba`: An error occurred during the execution of internal Word VBA macros.
|
|
2119
|
+
* - `pdf`: A failure occurred specifically during the PDF export phase.
|
|
2120
|
+
* - `noWin`: The operation requires Windows capabilities that are unavailable on the host OS.
|
|
2121
|
+
*/
|
|
2122
|
+
code;
|
|
2123
|
+
/**
|
|
2124
|
+
* Non-fatal warnings captured during the process *before* the fatal error was thrown.
|
|
2125
|
+
*/
|
|
2126
|
+
warnings;
|
|
2127
|
+
/**
|
|
2128
|
+
* Standard output and error streams aggregated from the underlying PowerShell shell session.
|
|
2129
|
+
*/
|
|
2130
|
+
powershellLog;
|
|
2131
|
+
/**
|
|
2132
|
+
* @param code - Machine-readable error code.
|
|
2133
|
+
* @param message - Human-readable error details.
|
|
2134
|
+
* @param renderedFile - Path to a partial output file, if any.
|
|
2135
|
+
* @param warnings - List of non-fatal warnings gathered prior to the exception.
|
|
2136
|
+
* @param powershellLog - List of shell execution strings collected during execution.
|
|
2137
|
+
* @param options - Standard native error options (e.g., to preserve the error `cause`).
|
|
2138
|
+
*/
|
|
2139
|
+
constructor(code, message, renderedFile, warnings = [], powershellLog, options) {
|
|
2140
|
+
super(message, options);
|
|
2141
|
+
this.name = "MDRenderError";
|
|
2142
|
+
this.code = code;
|
|
2143
|
+
this.renderedFile = renderedFile;
|
|
2144
|
+
this.warnings = warnings;
|
|
2145
|
+
this.powershellLog = powershellLog;
|
|
2146
|
+
if (Error.captureStackTrace)
|
|
2147
|
+
Error.captureStackTrace(this, _MDRenderError);
|
|
2148
|
+
}
|
|
2149
|
+
};
|
|
2150
|
+
function getAssetsDir() {
|
|
2151
|
+
if (typeof __dirname !== "undefined")
|
|
2152
|
+
return import_path4.default.resolve(__dirname, "../assets");
|
|
2153
|
+
const metaUrl = new Function("return import.meta.url")();
|
|
2154
|
+
return import_path4.default.resolve(import_path4.default.dirname((0, import_url.fileURLToPath)(metaUrl)), "../assets");
|
|
2155
|
+
}
|
|
2156
|
+
function getExtraProperties(configObj, allowedConfigKeys) {
|
|
2157
|
+
return Object.keys(configObj).filter(
|
|
2158
|
+
(key) => !allowedConfigKeys.includes(key)
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2162
|
+
0 && (module.exports = {
|
|
2163
|
+
MDRenderError
|
|
2164
|
+
});
|
|
2165
|
+
//# sourceMappingURL=index.cjs.map
|