md2gost 1.5.0 → 1.6.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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ const __MD2GOST_DIRNAME__ = __dirname;
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
@@ -31,18 +32,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
32
  var index_exports = {};
32
33
  __export(index_exports, {
33
34
  MDRenderError: () => MDRenderError,
35
+ UserInputError: () => UserInputError,
34
36
  default: () => renderMarkdown
35
37
  });
36
38
  module.exports = __toCommonJS(index_exports);
37
- var import_path4 = __toESM(require("path"));
38
- var import_url = require("url");
39
+ var import_path5 = __toESM(require("path"));
39
40
 
40
41
  // src/main.ts
41
- var import_path3 = __toESM(require("path"));
42
+ var import_path4 = __toESM(require("path"));
42
43
 
43
44
  // src/doc.ts
44
45
  var Doc = class {
45
46
  nodes = [];
47
+ header = { type: "none" };
48
+ footer = { type: "auto" };
46
49
  rainbow = false;
47
50
  numberingLazy = false;
48
51
  numberingSections = false;
@@ -102,36 +105,66 @@ var Doc = class {
102
105
  spacing: { before: void 0, after: void 0 },
103
106
  text: { size: void 0 }
104
107
  };
105
- appendText(text) {
106
- this.nodes.push({ type: "text", text });
108
+ formula = {
109
+ spacing: { before: 8, after: 8 }
110
+ };
111
+ admonition = {
112
+ note: { title: "**\u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435**", indent: 1.25, spacing: { before: 8, after: 8 }, padding: { top: 6, right: 10, bottom: 6, left: 10 }, background: "f5f5f5", color: "666666", bar_width: 2.25, icon: true, icon_size: 16, title_color: true },
113
+ info: { title: "**\u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435**", indent: 1.25, spacing: { before: 8, after: 8 }, padding: { top: 6, right: 10, bottom: 6, left: 10 }, background: "f0f7ff", color: "1976d2", bar_width: 2.25, icon: true, icon_size: 16, title_color: true },
114
+ tip: { title: "**\u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u044F**", indent: 1.25, spacing: { before: 8, after: 8 }, padding: { top: 6, right: 10, bottom: 6, left: 10 }, background: "f2f8f2", color: "2e7d32", bar_width: 2.25, icon: true, icon_size: 16, title_color: true },
115
+ warning: { title: "**\u0412\u043D\u0438\u043C\u0430\u043D\u0438\u0435**", indent: 1.25, spacing: { before: 8, after: 8 }, padding: { top: 6, right: 10, bottom: 6, left: 10 }, background: "fff7ea", color: "b26a00", bar_width: 2.25, icon: true, icon_size: 16, title_color: true },
116
+ danger: { title: "**\u041A\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0432\u0430\u0436\u043D\u043E**", indent: 1.25, spacing: { before: 8, after: 8 }, padding: { top: 6, right: 10, bottom: 6, left: 10 }, background: "fff0f0", color: "d32f2f", bar_width: 2.25, icon: true, icon_size: 16, title_color: true }
117
+ };
118
+ appendText(text, sourceLine) {
119
+ this.nodes.push({ type: "text", text, sourceLine });
107
120
  }
108
- appendTitle(text, level) {
109
- this.nodes.push({ type: "title", text, level });
121
+ appendTitle(text, level, sourceLine) {
122
+ this.nodes.push({ type: "title", text, level, sourceLine });
110
123
  }
111
124
  appendNode(node) {
112
125
  this.nodes.push(node);
113
126
  }
127
+ lineSkips = [];
128
+ addLineSkip(line, delta) {
129
+ this.lineSkips.push({ ln: line, d: delta });
130
+ }
131
+ mapSourceLine(line) {
132
+ for (const { ln, d } of this.lineSkips)
133
+ if (ln <= line) line -= d;
134
+ return line;
135
+ }
114
136
  };
115
- function tableRow(...items) {
116
- return items.map((v) => ({ type: "text", text: v }));
137
+ function tableRow(sourceLine, ...items) {
138
+ return items.map((v) => ({ type: "text", text: v, sourceLine }));
117
139
  }
118
140
 
119
141
  // src/parser.ts
120
- var import_promises2 = __toESM(require("fs/promises"));
142
+ var import_promises3 = __toESM(require("fs/promises"));
121
143
 
122
144
  // src/utils.ts
123
145
  var import_promises = __toESM(require("fs/promises"));
124
146
  var import_fs = __toESM(require("fs"));
125
147
  var path = __toESM(require("node:path"));
126
- function choice(...options) {
127
- return options[randomInt(options.length)];
148
+
149
+ // src/errors.ts
150
+ var UserInputError = class extends Error {
151
+ constructor(message) {
152
+ super(message);
153
+ }
154
+ };
155
+
156
+ // src/utils.ts
157
+ function choice(first, ...options) {
158
+ const all = [first, ...options];
159
+ return all[randomInt(all.length)];
128
160
  }
129
161
  function randomInt(maxmin, max, rnd = Math.random) {
130
162
  if (max != void 0)
131
- return Math.floor(rnd() * (maxmin - max)) + max;
163
+ return Math.floor(rnd() * (max - maxmin)) + maxmin;
132
164
  return Math.floor(rnd() * maxmin);
133
165
  }
134
166
  function trimEnd(str, ...chs) {
167
+ chs = chs.filter((ch) => ch.length > 0);
135
168
  if (!chs || chs.length == 0) return str.trimEnd();
136
169
  let trimmed = false;
137
170
  do {
@@ -145,6 +178,7 @@ function trimEnd(str, ...chs) {
145
178
  return str;
146
179
  }
147
180
  function trimStart(str, ...chs) {
181
+ chs = chs.filter((ch) => ch.length > 0);
148
182
  if (!chs || chs.length == 0) return str.trimStart();
149
183
  let trimmed = false;
150
184
  do {
@@ -160,10 +194,10 @@ function trimStart(str, ...chs) {
160
194
  function toCapitalCase(str) {
161
195
  return str.slice(0, 1).toUpperCase() + str.slice(1);
162
196
  }
163
- async function checkIfFileIsBlocked(path6) {
197
+ async function checkIfFileIsBlocked(path7) {
164
198
  let file;
165
199
  try {
166
- file = await import_promises.default.open(path6, "r+");
200
+ file = await import_promises.default.open(path7, "r+");
167
201
  return false;
168
202
  } catch (err) {
169
203
  if (!err) return false;
@@ -216,22 +250,791 @@ function realpathAllowMissing(inputPath) {
216
250
  function isMissingPathError(err) {
217
251
  return err instanceof Error && "code" in err && (err.code === "ENOENT" || err.code === "ENOTDIR");
218
252
  }
253
+ function getSafePathResolver(workdir, checkFilesIsInsidePath) {
254
+ const allowedRealPath = checkFilesIsInsidePath === false ? false : realpathAllowMissing(checkFilesIsInsidePath === "" ? workdir : checkFilesIsInsidePath);
255
+ const resolvePath = (fname, origin) => {
256
+ if (process.platform != "win32") fname = fname.replaceAll("\\", "/");
257
+ if (process.platform == "win32" && fname.startsWith("/")) fname = "." + fname;
258
+ const targetPath = path.isAbsolute(fname) ? path.resolve(fname) : path.resolve(origin || workdir, fname);
259
+ if (allowedRealPath !== false) {
260
+ const targetRealPath = realpathAllowMissing(targetPath);
261
+ const relative2 = path.relative(allowedRealPath, targetRealPath);
262
+ const isOutside = relative2 === ".." || relative2.startsWith(`..${path.sep}`) || path.isAbsolute(relative2);
263
+ if (isOutside) throw new UserInputError(`Access denied: "${fname}" resolves outside the working directory.`);
264
+ }
265
+ return targetPath;
266
+ };
267
+ const getRelative = (fname) => {
268
+ const targetPath = resolvePath(fname);
269
+ if (allowedRealPath !== false)
270
+ return path.relative(allowedRealPath, targetPath);
271
+ return path.relative(workdir, targetPath);
272
+ };
273
+ return { resolvePath, getRelative };
274
+ }
275
+ function isLocalFilePath(link) {
276
+ const value = link.trim();
277
+ if (value.startsWith("//")) return false;
278
+ if (path.win32.isAbsolute(value)) return true;
279
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value)) return false;
280
+ if (value.startsWith("#")) return false;
281
+ return true;
282
+ }
283
+ function deepOverwrite(target, source) {
284
+ const result = Object.assign(/* @__PURE__ */ Object.create(null), target);
285
+ for (const [key, sourceValue] of Object.entries(source)) {
286
+ if (key === "__proto__" || key === "prototype" || key === "constructor")
287
+ continue;
288
+ const targetValue = Object.hasOwn(result, key) ? result[key] : void 0;
289
+ result[key] = isJSONDict(targetValue) && isJSONDict(sourceValue) ? deepOverwrite(targetValue, sourceValue) : sourceValue;
290
+ }
291
+ return result;
292
+ function isJSONDict(value) {
293
+ return value !== null && typeof value === "object" && !Array.isArray(value);
294
+ }
295
+ }
219
296
 
220
297
  // src/parser.ts
298
+ var import_path2 = __toESM(require("path"));
299
+
300
+ // src/preprocessor.ts
301
+ var import_promises2 = __toESM(require("fs/promises"));
221
302
  var import_path = __toESM(require("path"));
222
- async function parseMD(file, logwarn = console.warn) {
223
- const lines = (await import_promises2.default.readFile(file, { encoding: "utf8" })).split("\n");
303
+ async function preprocess(file, variables, checkFilesIsInsidePath, options, signal, logwarn = console.warn) {
304
+ const rootFile = import_path.default.resolve(file);
305
+ const { resolvePath, getRelative } = getSafePathResolver(import_path.default.dirname(rootFile), checkFilesIsInsidePath);
306
+ const ctx = {
307
+ options,
308
+ workdir: import_path.default.dirname(rootFile),
309
+ includes: 0,
310
+ iterations: 0,
311
+ inputLength: 0,
312
+ generatedLength: 0,
313
+ signal: signal || void 0,
314
+ logwarn,
315
+ countAsOutput(v) {
316
+ ctx.generatedLength += v.length;
317
+ if (options.maxGeneratedLength !== void 0 && ctx.generatedLength > options.maxGeneratedLength)
318
+ throw new UserInputError(`Maximum output length exceeded (${options.maxGeneratedLength})`);
319
+ return v;
320
+ }
321
+ };
322
+ const rootNode = { type: "include", path: rootFile, dict: {}, trimEnd: false, trimStart: false };
323
+ return processInclude(rootNode, variables, resolvePath, getRelative, [], ctx);
324
+ }
325
+ async function processInclude(node, variables, resolvePath, getRelative, stack, ctx) {
326
+ ctx.signal?.throwIfAborted();
327
+ const fpath = resolvePath(node.path);
328
+ const relativePath = getRelative(fpath);
329
+ const dir = import_path.default.dirname(fpath);
330
+ if (ctx.options.maxIncludeDepth !== void 0 && stack.length > ctx.options.maxIncludeDepth)
331
+ throw new UserInputError(`Maximum include depth exceeded while including "${relativePath}":
332
+ ${stack.join(" -> ")}`);
333
+ if (stack.length > 0) {
334
+ ctx.includes++;
335
+ const maxIncludes = ctx.options.maxIncludes === void 0 ? 1e3 : ctx.options.maxIncludes;
336
+ if (ctx.includes > maxIncludes)
337
+ throw new UserInputError(`Maximum include count exceeded (${maxIncludes})`);
338
+ }
339
+ let rawContent;
340
+ try {
341
+ if (ctx.options.maxFileLength !== void 0) {
342
+ const size = (await import_promises2.default.stat(fpath)).size;
343
+ if (size > ctx.options.maxFileLength * 3)
344
+ throw new UserInputError(`File is too large (${size} > ${ctx.options.maxFileLength * 3}) "${relativePath}"`);
345
+ }
346
+ rawContent = await import_promises2.default.readFile(fpath, { encoding: "utf8", signal: ctx.signal });
347
+ if (ctx.options.maxFileLength !== void 0 && rawContent.length > ctx.options.maxFileLength)
348
+ throw new UserInputError(`File is too large (${rawContent.length} > ${ctx.options.maxFileLength}) "${relativePath}"`);
349
+ ctx.inputLength += rawContent.length;
350
+ if (ctx.options.maxTotalInputLength !== void 0 && ctx.inputLength > ctx.options.maxTotalInputLength)
351
+ throw new UserInputError(`Maximum total input length exceeded (${ctx.inputLength} > ${ctx.options.maxTotalInputLength})`);
352
+ } catch (err) {
353
+ ctx.signal?.throwIfAborted();
354
+ if (err instanceof UserInputError) throw err;
355
+ const reason = err instanceof Error ? err.message : String(err);
356
+ throw new UserInputError(`Failed to read included file "${relativePath}": ${reason}`);
357
+ }
358
+ let content = rawContent;
359
+ if (variables) {
360
+ variables = deepOverwrite(variables, node.dict);
361
+ const nodes = parseFExpr(rawContent);
362
+ nodes.forEach((n) => n.type == "expr" && (n.source.fname = relativePath));
363
+ content = processExpressions(nodes, variables || {}, ctx);
364
+ } else {
365
+ variables = {};
366
+ ctx.countAsOutput(content);
367
+ }
368
+ content = await fixLinks(content, fixLink);
369
+ if (!ctx.options.allowIncludes) return content;
370
+ const includes = await parseIncludes(content, ctx.logwarn);
371
+ let result = "";
372
+ for (const node2 of includes) {
373
+ if (node2.type == "text") result += node2.value;
374
+ else {
375
+ let r = await processInclude(node2, variables, resolvePath, getRelative, [...stack, relativePath], ctx);
376
+ if (node2.trimStart) r = r.trimStart();
377
+ if (node2.trimEnd) r = r.trimEnd();
378
+ result += r;
379
+ }
380
+ }
381
+ if (node.sourceLineCount) {
382
+ const delta = result.split("\n").length - node.sourceLineCount + 1;
383
+ result += "\n\uE100" + delta + "\uE101";
384
+ }
385
+ return result;
386
+ function fixLink(oldpath) {
387
+ oldpath = oldpath.trim();
388
+ oldpath = trimEnd(trimStart(oldpath, "<", '"'), ">", '"');
389
+ const newpath = !isLocalFilePath(oldpath) ? oldpath : import_path.default.relative(ctx.workdir, resolvePath(oldpath, dir)).split(import_path.default.sep).join("/");
390
+ if (newpath.includes(" ")) return `<${newpath}>`;
391
+ return newpath;
392
+ }
393
+ }
394
+ function parseFExpr(content) {
395
+ const nodes = [];
396
+ let textStart = 0;
397
+ let ln = 1;
398
+ function countLines(start, end) {
399
+ for (let i = start; i < end; i++)
400
+ if (content[i] == "\n") ln++;
401
+ }
402
+ function pushText(start, end) {
403
+ if (start >= end) return;
404
+ const value = content.slice(start, end);
405
+ const prev = nodes.at(-1);
406
+ countLines(start, end);
407
+ if (prev?.type == "text")
408
+ prev.value += value;
409
+ else
410
+ nodes.push({ type: "text", value });
411
+ }
412
+ function isEscaped(i) {
413
+ let slashes = 0;
414
+ for (i--; i >= 0 && content[i] == "\\"; i--)
415
+ slashes++;
416
+ return slashes % 2 != 0;
417
+ }
418
+ for (let i = 0; i < content.length; i++) {
419
+ if (content.startsWith("<!--", i)) {
420
+ const end2 = content.indexOf("-->", i + 4);
421
+ if (end2 < 0) break;
422
+ i = end2 + 2;
423
+ continue;
424
+ }
425
+ if (!content.startsWith("{{", i))
426
+ continue;
427
+ if (isEscaped(i)) {
428
+ pushText(textStart, i - 1);
429
+ pushText(i, i + 2);
430
+ textStart = i + 2;
431
+ i++;
432
+ continue;
433
+ }
434
+ const trimLeft = content[i + 2] == "-" && !/\d/.test(content[i + 3] || "");
435
+ const valueStart = i + 2 + (trimLeft ? 1 : 0);
436
+ let end = -1;
437
+ let inString = false;
438
+ let escaped = false;
439
+ for (let j = valueStart; j < content.length - 1; j++) {
440
+ const ch = content[j];
441
+ if (inString) {
442
+ if (escaped) escaped = false;
443
+ else if (ch === "\\") escaped = true;
444
+ else if (ch === '"') inString = false;
445
+ continue;
446
+ }
447
+ if (ch == '"') {
448
+ inString = true;
449
+ continue;
450
+ }
451
+ if (ch === "}" && content[j + 1] === "}") {
452
+ end = j;
453
+ break;
454
+ }
455
+ }
456
+ if (end < 0) continue;
457
+ const trimRight = end > valueStart && content[end - 1] == "-";
458
+ const valueEnd = trimRight ? end - 1 : end;
459
+ const hasQuotes = i > 0 && content[i - 1] == '"' && !isEscaped(i - 1) && content[end + 2] === '"';
460
+ let textEnd = hasQuotes ? i - 1 : i;
461
+ const untrimmedTextEnd = textEnd;
462
+ if (trimLeft)
463
+ while (textEnd > textStart && /\s/.test(content[textEnd - 1])) textEnd--;
464
+ pushText(textStart, textEnd);
465
+ countLines(textEnd, untrimmedTextEnd);
466
+ const lineStart = content.lastIndexOf("\n", i + 2);
467
+ const source = { ln, col: lineStart < 0 ? i + 1 : i - lineStart };
468
+ nodes.push({ type: "expr", value: content.slice(valueStart, valueEnd), hasQuotes, trimLeft, trimRight, source });
469
+ let next = hasQuotes ? end + 3 : end + 2;
470
+ if (trimRight) {
471
+ const untrimmedNext = next;
472
+ while (next < content.length && /\s/.test(content[next])) next++;
473
+ countLines(untrimmedNext, next);
474
+ }
475
+ textStart = next;
476
+ i = next - 1;
477
+ }
478
+ pushText(textStart, content.length);
479
+ return nodes;
480
+ }
481
+ function getByPath(value, path7) {
482
+ for (const key of path7) {
483
+ if (value === null || value === void 0)
484
+ return value;
485
+ const obj = Object(value);
486
+ if (!Object.hasOwn(obj, key))
487
+ return void 0;
488
+ value = obj[key];
489
+ }
490
+ return value;
491
+ }
492
+ function processExpressions(nodes, variables, ctx) {
493
+ const expr = parseExp(nodes, ctx);
494
+ const tree = buildExpTree(expr, ctx);
495
+ const res = execExpTree(tree, variables, ctx);
496
+ return res.join("");
497
+ }
498
+ function parseExp(nodes, ctx) {
499
+ const reVar = String.raw`[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*|\.\d+|\[\d+\])*`;
500
+ const reIdent = String.raw`[A-Za-z_$][A-Za-z0-9_$]*`;
501
+ const reStr = String.raw`"(?:\\.|[^"\\])*"`;
502
+ const reNum = String.raw`-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?`;
503
+ const reVal = String.raw`(?:${reStr}|${reNum}|true|false|null)`;
504
+ const reOCompare = String.raw`(?:==|!=|<|<=|>|>=|\bin\b)`;
505
+ const reOMath = String.raw`(?:\+|-|/|//|%|\*|\*\*)`;
506
+ const reOLogical = String.raw`(?:and|or|&&|\|\||\?\?)`;
507
+ const re_var = new RegExp(String.raw`^\s*((?:${reVar})|${reVal})\s*(?:(${reOMath}|${reOLogical})\s*((?:${reVar})|${reVal}))?\s*$`);
508
+ const re_val = new RegExp(String.raw`^${reVal}$`);
509
+ const re_str = new RegExp(String.raw`^\s*(${reStr})\s*$`);
510
+ const re_else = /^:else\s*$/;
511
+ const re_for = new RegExp(String.raw`^#for\s+(${reIdent})(?:\s*,\s*(${reIdent}))?\s+in\s+(${reVar}|${reNum}|${reStr})\s*$`);
512
+ const re_forEnd = /^\/for\s*$/;
513
+ const re_if = new RegExp(String.raw`^#if\s+((?:${reVar})|${reVal})\s*(?:(${reOCompare}|${reOLogical})\s*((?:${reVar})|${reVal}))?\s*$`);
514
+ const re_ifEnd = /^\/if\s*$/;
515
+ const re_path = /[A-Za-z_$][A-Za-z0-9_$]*|\d+/g;
516
+ return nodes.map((node) => {
517
+ ctx.signal?.throwIfAborted();
518
+ if (node.type == "text") return { type: "text", value: node.value };
519
+ const enode = node;
520
+ const source = node.source;
521
+ const expression = `{{${node.trimLeft ? "-" : ""}${node.value}${node.trimRight ? "-" : ""}}}`;
522
+ const rawValue = node.hasQuotes ? `"${expression}"` : expression;
523
+ function retWarn(msg) {
524
+ ctx.logwarn(msg + pos(enode));
525
+ return { type: "text", value: rawValue };
526
+ }
527
+ const mvar = re_var.exec(node.value);
528
+ if (mvar) {
529
+ const left = parseOperand(mvar[1]);
530
+ if (!left) return retWarn("Unsupported expression: " + rawValue);
531
+ const operator = mvar[2];
532
+ if (!operator) return { type: "var", left, source, hasQuotes: node.hasQuotes };
533
+ const right = parseOperand(mvar[3]);
534
+ if (!right) return retWarn("Unsupported expression: " + rawValue);
535
+ return { type: "var", left, operator, right, source, hasQuotes: node.hasQuotes };
536
+ }
537
+ const mstr = re_str.exec(node.value);
538
+ if (mstr) {
539
+ const str = safeParse(node.value);
540
+ if (str === void 0) return retWarn("Cant parse string: " + node.value);
541
+ return { type: "text", value: node.hasQuotes ? JSON.stringify(str) : `${str}` };
542
+ }
543
+ const mfor = re_for.exec(node.value);
544
+ if (mfor) {
545
+ if (!ctx.options.allowLoops) return retWarn("Loop expressions are not allowed");
546
+ const varValue = mfor[1];
547
+ const varKey = mfor[2];
548
+ const array = parseOperand(mfor[3]);
549
+ if (!array) return retWarn("Unsupported expression: " + rawValue);
550
+ return { type: "for", varValue, varKey, array, source };
551
+ }
552
+ const mif = re_if.exec(node.value);
553
+ if (mif) {
554
+ const left = parseOperand(mif[1]);
555
+ if (!left) return retWarn("Unsupported expression: " + rawValue);
556
+ const operator = mif[2];
557
+ if (!operator) return { type: "if", left, source };
558
+ const right = parseOperand(mif[3]);
559
+ if (!right) return retWarn("Unsupported expression: " + rawValue);
560
+ return { type: "if", left, operator, right, source };
561
+ }
562
+ if (re_else.exec(node.value)) return { type: "else", source };
563
+ if (re_ifEnd.exec(node.value)) return { type: "ifEnd", source };
564
+ if (re_forEnd.exec(node.value)) {
565
+ if (!ctx.options.allowLoops) return retWarn("Loop expressions are not allowed");
566
+ return { type: "forEnd", source };
567
+ }
568
+ return retWarn("Unsupported expression: " + rawValue);
569
+ });
570
+ function pos(node) {
571
+ return ` [Ln ${node.source.ln}, Col ${node.source.col}] (${node.source.fname})`;
572
+ }
573
+ function safeParse(value) {
574
+ try {
575
+ return JSON.parse(value);
576
+ } catch {
577
+ return void 0;
578
+ }
579
+ }
580
+ function parsePath(value) {
581
+ const parts = value?.match(re_path);
582
+ if (!parts?.length) return void 0;
583
+ return parts.map((part) => /^\d+$/.test(part) ? Number(part) : part);
584
+ }
585
+ function parseOperand(value) {
586
+ if (!value) return void 0;
587
+ if (re_val.test(value)) {
588
+ const val = safeParse(value);
589
+ if (val === void 0) return null;
590
+ return { t: "val", val };
591
+ }
592
+ const path7 = parsePath(value);
593
+ if (!path7) return null;
594
+ return { t: "var", path: path7 };
595
+ }
596
+ }
597
+ function buildExpTree(nodes, ctx, depth = 0, source) {
598
+ ctx.signal?.throwIfAborted();
599
+ if (ctx.options.maxDepth !== void 0 && depth >= ctx.options.maxDepth) {
600
+ ctx.logwarn(`Maximum expression nesting depth exceeded (${ctx.options.maxDepth})${source ? pos({ source }) : ""}`);
601
+ return nodes.map((n) => {
602
+ if (n.type == "text" || n.type == "var") return n;
603
+ if (n.type == "else" || n.type == "forEnd" || n.type == "ifEnd") {
604
+ const str = n.type == "else" ? "{{:else}}" : n.type == "ifEnd" ? "{{/if}}" : "{{/for}}";
605
+ return { type: "text", value: str };
606
+ }
607
+ if (n.type == "for") {
608
+ const second = n.varKey ? `, ${n.varKey}` : "";
609
+ return { type: "text", value: `{{#for ${n.varValue}${second} in ${strOperand(n.array)}}}` };
610
+ }
611
+ if (n.type == "if") {
612
+ const right = n.right ? ` ${n.operator} ${strOperand(n.right)}` : "";
613
+ return { type: "text", value: `{{#if ${strOperand(n.left)}${right}}}` };
614
+ }
615
+ n;
616
+ return { type: "text", value: "" };
617
+ });
618
+ }
619
+ const tree = [];
620
+ for (let i = 0; i < nodes.length; i++) {
621
+ const node = nodes[i];
622
+ if (node.type == "text" || node.type == "var") {
623
+ tree.push(node);
624
+ }
625
+ if (node.type == "else" || node.type == "forEnd" || node.type == "ifEnd") {
626
+ const str = node.type == "else" ? "{{:else}}" : node.type == "ifEnd" ? "{{/if}}" : "{{/for}}";
627
+ ctx.logwarn(`Unexpected expression (${str})` + pos(node));
628
+ tree.push({ type: "text", value: str });
629
+ }
630
+ if (node.type == "for" || node.type == "if") {
631
+ const r = parseBlockWithElse(i);
632
+ if (!r) {
633
+ if (node.type == "for") {
634
+ const second = node.varKey ? `, ${node.varKey}` : "";
635
+ tree.push({ type: "text", value: `{{#for ${node.varValue}${second} in ${strOperand(node.array)}}}` });
636
+ } else if (node.type == "if") {
637
+ const right = node.right ? ` ${node.operator} ${strOperand(node.right)}` : "";
638
+ tree.push({ type: "text", value: `{{#if ${strOperand(node.left)}${right}}}` });
639
+ }
640
+ } else {
641
+ const { body, bodyElse, endI } = r;
642
+ i = endI;
643
+ tree.push({ ...node, body, bodyElse });
644
+ }
645
+ }
646
+ }
647
+ return tree;
648
+ function pos(node) {
649
+ return ` [Ln ${node.source.ln}, Col ${node.source.col}] (${node.source.fname})`;
650
+ }
651
+ function strOperand(v) {
652
+ return v.t == "val" ? JSON.stringify(v.val) : v.path.join(".");
653
+ }
654
+ function findBlockEnd(startI, type, skipElse) {
655
+ const stack = [];
656
+ for (let i = startI; i < nodes.length; i++) {
657
+ const node = nodes[i];
658
+ if (node.type == "if") stack.push("if");
659
+ else if (node.type == "for") stack.push("for");
660
+ else if (node.type == "forEnd" && stack.at(-1) == "for") stack.pop();
661
+ else if (node.type == "ifEnd" && stack.at(-1) == "if") stack.pop();
662
+ else if (stack.length == 0) {
663
+ if (node.type == "else" && !skipElse) return i;
664
+ if (node.type == "forEnd" && type == "for") return i;
665
+ if (node.type == "ifEnd" && type == "if") return i;
666
+ }
667
+ }
668
+ return -1;
669
+ }
670
+ function parseBlockWithElse(startI) {
671
+ const node = nodes[startI];
672
+ if (node.type != "for" && node.type != "if") return null;
673
+ const n = node;
674
+ const type = n.type;
675
+ const unclosed = (m) => ctx.logwarn(`Unclosed ${type} ${m}` + pos(n));
676
+ const bodyEnd = findBlockEnd(startI + 1, type, false);
677
+ if (bodyEnd < 0) {
678
+ unclosed("body");
679
+ return null;
680
+ }
681
+ const bodyNodes = nodes.slice(startI + 1, bodyEnd);
682
+ const body = buildExpTree(bodyNodes, ctx, depth + 1, n.source);
683
+ let endI = bodyEnd;
684
+ let bodyElse;
685
+ if (nodes[bodyEnd].type == "else") {
686
+ const bodyElseEnd = findBlockEnd(bodyEnd + 1, type, true);
687
+ if (bodyElseEnd < 0) {
688
+ unclosed("else block");
689
+ return null;
690
+ }
691
+ const bodyElseNodes = nodes.slice(bodyEnd + 1, bodyElseEnd);
692
+ bodyElse = buildExpTree(bodyElseNodes, ctx, depth + 1, n.source);
693
+ endI = bodyElseEnd;
694
+ }
695
+ return { body, bodyElse, endI };
696
+ }
697
+ }
698
+ function execExpTree(tree, variables, ctx) {
699
+ return tree.flatMap((node) => {
700
+ ctx.signal?.throwIfAborted();
701
+ if (node.type == "text") return ctx.countAsOutput(node.value);
702
+ if (node.type == "var") {
703
+ const n = node;
704
+ const value = execOperator(node.left, node.operator, node.right);
705
+ const rawValue = () => {
706
+ const right = n.right ? ` ${n.operator} ${strOperand(n.right)}` : "";
707
+ const value2 = `{{${strOperand(n.left)}${right}}}`;
708
+ return n.hasQuotes ? `"${value2}"` : value2;
709
+ };
710
+ if (value === void 0) ctx.logwarn("Undefined variable: " + rawValue() + pos(node));
711
+ const result = value === void 0 ? rawValue() : typeof value == "object" || node.hasQuotes ? JSON.stringify(value) : `${value}`;
712
+ return ctx.countAsOutput(result);
713
+ }
714
+ if (node.type == "if") {
715
+ const res = execOperator(node.left, node.operator, node.right);
716
+ const result = res && typeof res == "object" ? (Array.isArray(res) ? res : Object.keys(res)).length > 0 : !!res;
717
+ if (result) return execExpTree(node.body, variables, ctx);
718
+ if (node.bodyElse) return execExpTree(node.bodyElse, variables, ctx);
719
+ return "";
720
+ }
721
+ if (node.type == "for") {
722
+ if (!ctx.options.allowLoops) throw new UserInputError("Loop expressions are not allowed");
723
+ const arr = node.array.t == "val" ? node.array.val : getByPath(variables, node.array.path);
724
+ if (!arr || typeof arr == "object" && (Array.isArray(arr) ? arr : Object.keys(arr)).length == 0) {
725
+ if (node.bodyElse) return execExpTree(node.bodyElse, variables, ctx);
726
+ return "";
727
+ }
728
+ const values = (() => {
729
+ const n = node;
730
+ function checkLoopIterations(count, final = true) {
731
+ const max = ctx.options.maxLoopIterations === void 0 ? 1e3 : ctx.options.maxLoopIterations;
732
+ if (count > max)
733
+ throw new UserInputError(`Maximum loop iterations exceeded (${final ? count + " " : ""}> ${max})` + pos(n));
734
+ if (ctx.options.maxTotalIterations !== void 0 && ctx.iterations + count > ctx.options.maxTotalIterations)
735
+ throw new UserInputError(`Maximum total loop iterations exceeded (${ctx.options.maxTotalIterations})`);
736
+ }
737
+ if (typeof arr == "number" && Number.isInteger(arr)) {
738
+ if (arr < 0) {
739
+ ctx.logwarn(`For loop source is a negative integer (${arr})` + pos(node));
740
+ return [];
741
+ }
742
+ checkLoopIterations(arr);
743
+ return Array.from({ length: arr }, (_, i) => ({ k: i, v: i + 1 }));
744
+ }
745
+ if (typeof arr == "object") {
746
+ if (Array.isArray(arr)) {
747
+ checkLoopIterations(arr.length);
748
+ return arr.map((v, i) => ({ k: i, v }));
749
+ }
750
+ const keys = Object.keys(arr);
751
+ checkLoopIterations(keys.length);
752
+ return keys.map((k) => ({ k, v: arr[k] }));
753
+ }
754
+ if (typeof arr == "string") {
755
+ const values2 = [];
756
+ for (const v of arr) {
757
+ values2.push({ k: values2.length, v });
758
+ checkLoopIterations(values2.length, false);
759
+ }
760
+ return values2;
761
+ }
762
+ })();
763
+ if (!values) {
764
+ ctx.logwarn(`For loop source is not object, string or integer (${arr})` + pos(node));
765
+ return "";
766
+ }
767
+ return values.flatMap(({ k, v }) => {
768
+ ctx.signal?.throwIfAborted();
769
+ ctx.iterations++;
770
+ if (ctx.options.maxTotalIterations !== void 0 && ctx.iterations > ctx.options.maxTotalIterations)
771
+ throw new UserInputError(`Maximum total loop iterations exceeded (${ctx.options.maxTotalIterations})`);
772
+ const locals = Object.assign(/* @__PURE__ */ Object.create(null), variables);
773
+ locals[node.varValue] = v;
774
+ if (node.varKey) locals[node.varKey] = k;
775
+ return execExpTree(node.body, locals, ctx);
776
+ });
777
+ }
778
+ node;
779
+ return "";
780
+ });
781
+ function pos(node) {
782
+ return ` [Ln ${node.source.ln}, Col ${node.source.col}] (${node.source.fname})`;
783
+ }
784
+ function strOperand(v) {
785
+ return v.t == "val" ? JSON.stringify(v.val) : v.path.join(".");
786
+ }
787
+ function isEqual(obj1, obj2) {
788
+ if (obj1 === obj2) return true;
789
+ if (obj1 == null || obj2 == null || typeof obj1 !== "object" || typeof obj2 !== "object")
790
+ return obj1 == obj2;
791
+ const keys1 = Object.keys(obj1);
792
+ const keys2 = Object.keys(obj2);
793
+ if (keys1.length !== keys2.length) return false;
794
+ for (const key of keys1)
795
+ if (!Object.hasOwn(obj2, key) || !isEqual(obj1[key], obj2[key]))
796
+ return false;
797
+ return true;
798
+ }
799
+ function execOperator(left, operator, right) {
800
+ const leftV = left.t == "val" ? left.val : getByPath(variables, left.path);
801
+ if (!operator || !right) return leftV;
802
+ const rightV = right.t == "val" ? right.val : getByPath(variables, right.path);
803
+ if (operator == "==") return isEqual(leftV, rightV);
804
+ if (operator == "!=") return !isEqual(leftV, rightV);
805
+ if (operator == "<=") return leftV < rightV || isEqual(leftV, rightV);
806
+ if (operator == ">=") return leftV > rightV || isEqual(leftV, rightV);
807
+ if (operator == "<") return leftV < rightV;
808
+ if (operator == ">") return leftV > rightV;
809
+ if (operator == "in") return !!rightV && typeof rightV == "object" && (Array.isArray(rightV) ? rightV : Object.keys(rightV)).some((v) => isEqual(v, leftV));
810
+ if (operator == "and" || operator == "&&") return leftV && rightV;
811
+ if (operator == "or" || operator == "||") return leftV || rightV;
812
+ if (operator == "??") return leftV ?? rightV;
813
+ if (operator == "+") return leftV + rightV;
814
+ if (operator == "-") return leftV - rightV;
815
+ if (operator == "*") return leftV * rightV;
816
+ if (operator == "**") return Math.pow(leftV, rightV);
817
+ if (operator == "/") return rightV == 0 ? 0 : leftV / rightV;
818
+ if (operator == "//") return Math.floor(rightV == 0 ? 0 : leftV / rightV);
819
+ if (operator == "%") return rightV == 0 ? 0 : leftV % rightV;
820
+ operator;
821
+ return false;
822
+ }
823
+ }
824
+ function parseIncludePath(value) {
825
+ value = value.trim();
826
+ const trimLeft = value.startsWith("-");
827
+ if (trimLeft) value = value.slice(1).trimStart();
828
+ const trimLeftInner = value.startsWith("-");
829
+ if (trimLeftInner) value = value.slice(1).trimStart();
830
+ const trimRight = value.endsWith("-");
831
+ if (trimRight) value = value.slice(0, -1).trimEnd();
832
+ const trimRightInner = value.endsWith("-");
833
+ if (trimRightInner) value = value.slice(0, -1).trimEnd();
834
+ const path7 = trimEnd(trimStart(value, "<", '"'), ">", '"');
835
+ return { path: path7, trimLeft, trimLeftInner, trimRight, trimRightInner };
836
+ }
837
+ function findClosingBrace(content, start) {
838
+ let depth = 0;
839
+ let inString = false;
840
+ let lineComment = false;
841
+ let blockComment = false;
842
+ for (let i = start; i < content.length; i++) {
843
+ const ch = content[i];
844
+ if (lineComment) {
845
+ if (ch == "\n") lineComment = false;
846
+ continue;
847
+ }
848
+ if (blockComment) {
849
+ if (ch == "*" && content[i + 1] == "/") {
850
+ blockComment = false;
851
+ i++;
852
+ }
853
+ continue;
854
+ }
855
+ if (inString) {
856
+ if (ch == "\\") i++;
857
+ else if (ch == '"') inString = false;
858
+ continue;
859
+ }
860
+ if (ch == '"') {
861
+ inString = true;
862
+ continue;
863
+ }
864
+ if (ch == "/" && content[i + 1] == "/") {
865
+ lineComment = true;
866
+ i++;
867
+ continue;
868
+ }
869
+ if (ch == "/" && content[i + 1] == "*") {
870
+ blockComment = true;
871
+ i++;
872
+ continue;
873
+ }
874
+ if (ch == "{") depth++;
875
+ else if (ch == "}" && --depth == 0) return i;
876
+ }
877
+ return -1;
878
+ }
879
+ async function parseIncludes(content, logwarn) {
880
+ const { default: JSONC } = await import("jsonc-simple-parser");
881
+ const re_doc = /^!!\(([^{}]*)\)\s*{(.*)}$/s;
882
+ const re_codeFence = /^( {0,3})(`{3,})([^`]*)$/;
883
+ const nodes = [];
884
+ let textStart = 0;
885
+ function pushText(start, end) {
886
+ if (start >= end) return;
887
+ const value = content.slice(start, end);
888
+ const prev = nodes.at(-1);
889
+ if (prev?.type === "text")
890
+ prev.value += value;
891
+ else
892
+ nodes.push({ type: "text", value });
893
+ }
894
+ let codeFence = 0;
895
+ for (let i = 0; i < content.length; i++) {
896
+ if (i != 0 && content[i - 1] != "\n") continue;
897
+ const lineEnd = content.indexOf("\n", i);
898
+ const line = content.slice(i, lineEnd < 0 ? content.length : lineEnd).replace(/\r$/, "");
899
+ const m_fence = re_codeFence.exec(line);
900
+ if (m_fence) {
901
+ const ticks = m_fence[2].length;
902
+ const suffix = m_fence[3];
903
+ if (codeFence == 0) {
904
+ codeFence = ticks;
905
+ continue;
906
+ }
907
+ if (ticks >= codeFence && suffix.trim() == "") {
908
+ codeFence = 0;
909
+ continue;
910
+ }
911
+ }
912
+ if (codeFence != 0) continue;
913
+ if (content.slice(i, i + 2) !== "!!") continue;
914
+ const m_start = /^!!\([^{}]*\)\s*{/.exec(content.slice(i));
915
+ if (!m_start) continue;
916
+ const end = findClosingBrace(content, i + m_start[0].length - 1);
917
+ if (end < 0) continue;
918
+ const block = content.slice(i, end + 1);
919
+ const m_doc = re_doc.exec(block);
920
+ if (!m_doc) continue;
921
+ const { path: path7, trimLeft, trimLeftInner, trimRight, trimRightInner } = parseIncludePath(m_doc[1]);
922
+ if (!path7.toLowerCase().endsWith(".md")) continue;
923
+ let dict = {};
924
+ try {
925
+ dict = JSONC.parse(`{${m_doc[2]}}`);
926
+ } catch {
927
+ logwarn(`Can't parse include dict: {${m_doc[2].replaceAll("\n", " ")}}`);
928
+ continue;
929
+ }
930
+ let textEnd = i;
931
+ if (trimLeft)
932
+ while (textEnd > textStart && /\s/.test(content[textEnd - 1])) textEnd--;
933
+ pushText(textStart, textEnd);
934
+ nodes.push({ type: "include", path: path7, dict, sourceLineCount: block.split("\n").length, trimStart: trimLeftInner, trimEnd: trimRightInner });
935
+ let next = end + 1;
936
+ if (trimRight)
937
+ while (next < content.length && /\s/.test(content[next])) next++;
938
+ textStart = next;
939
+ i = next - 1;
940
+ }
941
+ pushText(textStart, content.length);
942
+ return nodes;
943
+ }
944
+ async function fixLinks(content, fixLink) {
945
+ const { default: JSONC } = await import("jsonc-simple-parser");
946
+ const re_codeFence = /^( {0,3})(`{3,})([^`]*)$/;
947
+ let result = "";
948
+ let textStart = 0;
949
+ function append(start, end) {
950
+ if (start >= end) return;
951
+ result += content.slice(start, end);
952
+ }
953
+ let codeFence = 0;
954
+ for (let i = 0; i < content.length; i++) {
955
+ if (i != 0 && content[i - 1] != "\n") continue;
956
+ const lineEnd = content.indexOf("\n", i);
957
+ const lineTextEnd = lineEnd < 0 ? content.length : lineEnd - (content[lineEnd - 1] == "\r" ? 1 : 0);
958
+ const line = content.slice(i, lineTextEnd);
959
+ const m_fence = re_codeFence.exec(line);
960
+ if (m_fence) {
961
+ const ticks = m_fence[2].length;
962
+ const suffix = m_fence[3];
963
+ if (codeFence == 0) {
964
+ codeFence = ticks;
965
+ continue;
966
+ }
967
+ if (ticks >= codeFence && suffix.trim() == "") {
968
+ codeFence = 0;
969
+ continue;
970
+ }
971
+ }
972
+ if (codeFence != 0) continue;
973
+ if (content.at(i) != "!") continue;
974
+ const m_img = /^!\[(.*)\]\((.*)\)({(.*)})?$/.exec(line);
975
+ if (m_img) {
976
+ append(textStart, i);
977
+ result += `![${m_img[1]}](${fixLink(m_img[2])})${m_img[3] || ""}`;
978
+ textStart = lineTextEnd;
979
+ i = lineEnd < 0 ? content.length : lineEnd;
980
+ continue;
981
+ }
982
+ const m_start = /^!!\([^{}]*\)\s*{/.exec(content.slice(i));
983
+ if (!m_start) continue;
984
+ const end = findClosingBrace(content, i + m_start[0].length - 1);
985
+ if (end < 0) continue;
986
+ const block = content.slice(i, end + 1);
987
+ const m_doc = /^!!\(([^{}]*)\)(\s*{(.*)})$/s.exec(block);
988
+ if (!m_doc) continue;
989
+ try {
990
+ JSONC.parse(m_doc[2].trim());
991
+ } catch {
992
+ continue;
993
+ }
994
+ const { path: path7, trimLeft, trimLeftInner, trimRight, trimRightInner } = parseIncludePath(m_doc[1]);
995
+ let fixedPath = fixLink(path7);
996
+ if (fixedPath.startsWith("-") || fixedPath.endsWith("-"))
997
+ fixedPath = `"${fixedPath}"`;
998
+ append(textStart, i);
999
+ result += `!!(${trimLeft ? "-" : ""}${trimLeftInner ? "-" : ""}${fixedPath}${trimRightInner ? "-" : ""}${trimRight ? "-" : ""})${m_doc[2]}`;
1000
+ textStart = end + 1;
1001
+ i = end;
1002
+ }
1003
+ append(textStart, content.length);
1004
+ return result;
1005
+ }
1006
+
1007
+ // src/parser.ts
1008
+ async function parseMD(file, variables, templateOptions = {}, checkFilesIsInsidePath = false, signal, logwarn = console.warn) {
1009
+ signal?.throwIfAborted();
1010
+ const preprocessed = await preprocess(file, variables, checkFilesIsInsidePath, templateOptions, signal, logwarn);
1011
+ signal?.throwIfAborted();
1012
+ const lines = preprocessed.split("\n");
224
1013
  const doc = new Doc();
1014
+ const warnAt = (line, message) => logwarn(`Line ${doc.mapSourceLine(line)}: ${message}`);
1015
+ (function processLineSkips() {
1016
+ for (let i = 0; i < lines.length; i++) {
1017
+ const line = lines[i];
1018
+ if (line.at(0) != "\uE100") continue;
1019
+ const m = /\uE100(-?\d+)\uE101/.exec(line);
1020
+ if (!m) {
1021
+ lines[i] = line.replaceAll("\uE100", "").replaceAll("\uE101", "");
1022
+ continue;
1023
+ }
1024
+ lines[i] = line.slice(m?.[0].length);
1025
+ doc.addLineSkip(i + 1, parseInt(m[1]));
1026
+ }
1027
+ })();
225
1028
  try {
226
- doc.title = toCapitalCase(trimEnd(import_path.default.parse(file).name, ".g"));
227
- const stats = await import_promises2.default.stat(file);
1029
+ doc.title = toCapitalCase(trimEnd(import_path2.default.parse(file).name, ".g"));
1030
+ const stats = await import_promises3.default.stat(file);
228
1031
  doc.ctime = stats.birthtime;
229
1032
  } catch {
230
1033
  }
231
1034
  function parseList(text, parts, ordered, level = 0) {
232
1035
  const startIndex = isFinite(parseInt(parts[0])) ? parseInt(parts[0]) : 1;
233
1036
  const mark = ordered ? parts[1] == "." ? "." : ")" : parts[1] == "*" ? "*" : "-";
234
- const node = { type: "list", ordered, mark, startIndex, items: [{ type: "listItem", text }] };
1037
+ const node = { type: "list", ordered, mark, startIndex, sourceLine: lineI, items: [{ type: "listItem", text, sourceLine: lineI }] };
235
1038
  const P = ordered ? "1)" : "*";
236
1039
  function skipEmptyLines() {
237
1040
  let emptyFound = false;
@@ -263,7 +1066,7 @@ async function parseMD(file, logwarn = console.warn) {
263
1066
  if (ln.prefix == "" && last?.type == "listItem")
264
1067
  last.text += "\n" + ln.text;
265
1068
  else if (ln.prefix == P)
266
- node.items.push({ type: "listItem", text: ln.text });
1069
+ node.items.push({ type: "listItem", text: ln.text, sourceLine: lineI + 1 });
267
1070
  else break;
268
1071
  } else if (ln.level > level) {
269
1072
  if (ln.level == level + 1) ln = parseLine(ln.text);
@@ -292,19 +1095,19 @@ async function parseMD(file, logwarn = console.warn) {
292
1095
  if (isFinite(h)) height = h;
293
1096
  }
294
1097
  const src = trimEnd(trimStart(parts[1], "<"), ">");
295
- return { type: "image", text, src, width, height };
1098
+ return { type: "image", text, src, width, height, sourceLine: lineI };
296
1099
  }
297
1100
  function parseCode(text) {
298
1101
  const header = text.split(" ");
299
1102
  const title = header.slice(1).join(" ").trim() || void 0;
300
- const node = { type: "code", lang: header[0], title, code: "" };
301
- text = "";
1103
+ const node = { type: "code", lang: header[0], title, code: "", sourceLine: lineI };
1104
+ const code = [];
302
1105
  while (lineI < lines.length) {
303
1106
  const ln = lines[lineI++];
304
1107
  if (ln.startsWith("```")) break;
305
- text += "\n" + ln;
1108
+ code.push(ln);
306
1109
  }
307
- node.code = text.trim();
1110
+ node.code = code.join("\n");
308
1111
  return node;
309
1112
  }
310
1113
  function parseSection(text) {
@@ -317,9 +1120,78 @@ async function parseMD(file, logwarn = console.warn) {
317
1120
  return {
318
1121
  type: "sectionBreak",
319
1122
  pageStart: unpaged ? -1 : isFinite(num) ? num : null,
320
- orientation: portrait ? "portrait" : landscape ? "landscape" : null
1123
+ orientation: portrait ? "portrait" : landscape ? "landscape" : null,
1124
+ sourceLine: lineI
321
1125
  };
322
1126
  }
1127
+ function parseHeaderFooter(kind, options) {
1128
+ const value = options.trim().toLowerCase();
1129
+ if (value == "none" || kind == "footer" && value == "auto") {
1130
+ setHeaderFooter(kind, { type: value });
1131
+ return;
1132
+ }
1133
+ const align = value == "" ? "left" : /^align=(left|center|right)$/.exec(value)?.[1];
1134
+ if (!align) {
1135
+ warnAt(lineI, `Wrong ${kind} options: "${options}". Expected align=left, align=center, align=right${kind == "footer" ? ", none, or auto" : ", or none"}.`);
1136
+ return;
1137
+ }
1138
+ const end = `!!end${kind}`;
1139
+ const content = [];
1140
+ const initialLineI = lineI;
1141
+ let closed = false;
1142
+ while (lineI < lines.length) {
1143
+ const line = lines[lineI++];
1144
+ if (line.trim().toLowerCase() == end) {
1145
+ closed = true;
1146
+ break;
1147
+ }
1148
+ content.push(line);
1149
+ }
1150
+ if (!closed) {
1151
+ lineI = initialLineI;
1152
+ warnAt(initialLineI, `${kind} block is not closed`);
1153
+ return;
1154
+ }
1155
+ const nodes = [{ type: "text", text: content.join("\n").trim(), sourceLine: initialLineI + 1 }];
1156
+ findTables(nodes, false);
1157
+ const supported = nodes.filter((node) => node.type == "text" || node.type == "table");
1158
+ if (supported.length != 1 || supported[0]?.type == "text" && !supported[0].text) {
1159
+ warnAt(initialLineI, `${kind} must contain text or one table`);
1160
+ return;
1161
+ }
1162
+ setHeaderFooter(kind, { type: "content", align, nodes: supported });
1163
+ function setHeaderFooter(kind2, value2) {
1164
+ let section;
1165
+ for (let i = doc.nodes.length - 1; i >= 0; i--) {
1166
+ if (doc.nodes[i]?.type == "sectionBreak") {
1167
+ section = doc.nodes[i];
1168
+ break;
1169
+ }
1170
+ }
1171
+ if (section?.type == "sectionBreak") section[kind2] = value2;
1172
+ else doc[kind2] = value2;
1173
+ }
1174
+ }
1175
+ function parseAdmonition(parts) {
1176
+ const marker = parts[0];
1177
+ const type = parts[1];
1178
+ const title = parts[2];
1179
+ const attributes = parts[3];
1180
+ const content = [];
1181
+ const close = new RegExp(`^${marker}\\s*$`);
1182
+ const initialLineI = lineI;
1183
+ let closed = false;
1184
+ while (lineI < lines.length) {
1185
+ const line = lines[lineI++];
1186
+ if (close.test(line)) {
1187
+ closed = true;
1188
+ break;
1189
+ }
1190
+ content.push(line);
1191
+ }
1192
+ if (!closed) warnAt(initialLineI, `Admonition "${type}" is not closed`);
1193
+ return { type: "admonition", admonitionType: type, title, text: content.filter((t) => !!t.trim()).join("\n").trim(), attributes, sourceLine: initialLineI };
1194
+ }
323
1195
  class RuleError extends Error {
324
1196
  }
325
1197
  ;
@@ -389,9 +1261,43 @@ async function parseMD(file, logwarn = console.warn) {
389
1261
  "text spacing after": (v) => doc.text.spacing.after = tryParseInt(v),
390
1262
  "img text size": (v) => doc.img.text.size = tryParseInt(v),
391
1263
  "img spacing before": (v) => doc.img.spacing.before = tryParseInt(v),
392
- "img spacing after": (v) => doc.img.spacing.after = tryParseInt(v)
1264
+ "img spacing after": (v) => doc.img.spacing.after = tryParseInt(v),
1265
+ "formula spacing before": (v) => doc.formula.spacing.before = tryParseInt(v),
1266
+ "formula spacing after": (v) => doc.formula.spacing.after = tryParseInt(v)
393
1267
  };
394
1268
  const reRules = [
1269
+ {
1270
+ re: /^(admonition (all|note|info|tip|warning|danger) (spacing (before|after)|padding|indent|background|color|bar_width|icon size|icon|title_color|title))(.*)/,
1271
+ n: (m) => ({ rule: m[1], value: (m.at(-1) || "").trim() }),
1272
+ f(m) {
1273
+ const type = m[2];
1274
+ const property = m[3];
1275
+ const value = (m.at(-1) || "").trim();
1276
+ const valueKeepCase = text.slice(m[1].length).trim();
1277
+ const types = type == "all" ? ["note", "info", "tip", "warning", "danger"] : [type];
1278
+ for (const type2 of types) {
1279
+ const style = doc.admonition[type2];
1280
+ if (property == "spacing before") style.spacing.before = tryParseInt(value);
1281
+ else if (property == "spacing after") style.spacing.after = tryParseInt(value);
1282
+ else if (property == "indent") style.indent = tryParseFloat(value);
1283
+ else if (property == "padding") {
1284
+ const padding = value.split(" ").map(tryParseInt);
1285
+ if (padding.length != 2) throw new RuleError("Two values are required: horizontal vertical");
1286
+ style.padding = { top: padding[1], right: padding[0], bottom: padding[1], left: padding[0] };
1287
+ } else if (property == "background") style.background = tryParseColor(value);
1288
+ else if (property == "color") style.color = tryParseColor(value);
1289
+ else if (property == "bar_width") style.bar_width = tryParseFloat(value);
1290
+ else if (property == "icon size") style.icon_size = tryParseInt(value);
1291
+ else if (property == "icon") {
1292
+ choices(value, "on", "off");
1293
+ style.icon = value == "on";
1294
+ } else if (property == "title_color") {
1295
+ choices(value, "on", "off");
1296
+ style.title_color = value == "on";
1297
+ } else if (property == "title") style.title = valueKeepCase;
1298
+ }
1299
+ }
1300
+ },
395
1301
  {
396
1302
  re: /^(headings (h[1-6])(\+?) (size|spacing (before|after)|uppercase|indent))(.*)/,
397
1303
  n: (m) => ({ rule: m[1], value: (m.at(-1) || "").trim() }),
@@ -429,11 +1335,11 @@ async function parseMD(file, logwarn = console.warn) {
429
1335
  rule = n.rule;
430
1336
  value = n.value;
431
1337
  }
432
- if (e instanceof RuleError) logwarn(`Rule "${rule}" wrong value: "${value}". ${e.message}`);
1338
+ if (e instanceof RuleError) warnAt(lineI, `Rule "${rule}" wrong value: "${value}". ${e.message}`);
433
1339
  else throw e;
434
1340
  }
435
1341
  } else {
436
- logwarn(`Wrong rule: "${text}"`);
1342
+ warnAt(lineI, `Wrong rule: "${text}"`);
437
1343
  }
438
1344
  function tryParseInt(v) {
439
1345
  const num = parseInt(v);
@@ -450,6 +1356,11 @@ async function parseMD(file, logwarn = console.warn) {
450
1356
  if (!isFinite(date.valueOf())) throw new RuleError("Only ISO 8601 date is allowed");
451
1357
  return date;
452
1358
  }
1359
+ function tryParseColor(v) {
1360
+ const color = /^#?([\da-f]{6})$/i.exec(v)?.[1];
1361
+ if (!color) throw new RuleError("Only #RRGGBB colors are allowed");
1362
+ return color;
1363
+ }
453
1364
  function choices(v, ...vars) {
454
1365
  if (vars.includes(v)) return v;
455
1366
  throw new RuleError("Allowed: " + vars.join(", "));
@@ -463,66 +1374,85 @@ async function parseMD(file, logwarn = console.warn) {
463
1374
  while (lineI < lines.length) {
464
1375
  const line = lines[lineI++];
465
1376
  const { prefix, text, parts } = parseLine(line);
466
- switch (prefix) {
467
- case "#":
468
- doc.appendTitle(text, 1);
469
- break;
470
- case "##":
471
- doc.appendTitle(text, 2);
472
- break;
473
- case "###":
474
- doc.appendTitle(text, 3);
475
- break;
476
- case "####":
477
- doc.appendTitle(text, 4);
478
- break;
479
- case "#####":
480
- doc.appendTitle(text, 5);
481
- break;
482
- case "######":
483
- doc.appendTitle(text, 6);
484
- break;
485
- case "*":
486
- doc.appendNode(parseList(text, parts, false));
487
- break;
488
- case "1)":
489
- doc.appendNode(parseList(text, parts, true));
490
- break;
491
- case "Img":
492
- doc.appendNode(parseImg(parts));
493
- break;
494
- case "Code":
495
- doc.appendNode(parseCode(text));
496
- break;
497
- case "Comment":
498
- skipComment();
499
- break;
500
- case "!!section":
501
- doc.appendNode(parseSection(text));
502
- break;
503
- case "!!rule":
504
- apllyRule(text);
505
- break;
506
- case "---":
507
- doc.appendNode({ type: "pageBreak" });
508
- break;
509
- case "":
510
- case " ":
511
- const last = doc.nodes.at(-1);
512
- if (line.trim() != "" && last?.type == "text") {
513
- if (last.text != "") last.text += "\n";
514
- last.text += line.trim();
515
- } else doc.appendText(line.trim());
516
- break;
517
- default:
518
- prefix;
519
- throw new Error("switch default");
1377
+ try {
1378
+ switch (prefix) {
1379
+ case "#":
1380
+ doc.appendTitle(text, 1, lineI);
1381
+ break;
1382
+ case "##":
1383
+ doc.appendTitle(text, 2, lineI);
1384
+ break;
1385
+ case "###":
1386
+ doc.appendTitle(text, 3, lineI);
1387
+ break;
1388
+ case "####":
1389
+ doc.appendTitle(text, 4, lineI);
1390
+ break;
1391
+ case "#####":
1392
+ doc.appendTitle(text, 5, lineI);
1393
+ break;
1394
+ case "######":
1395
+ doc.appendTitle(text, 6, lineI);
1396
+ break;
1397
+ case "*":
1398
+ doc.appendNode(parseList(text, parts, false));
1399
+ break;
1400
+ case "1)":
1401
+ doc.appendNode(parseList(text, parts, true));
1402
+ break;
1403
+ case "Img":
1404
+ doc.appendNode(parseImg(parts));
1405
+ break;
1406
+ case "Code":
1407
+ doc.appendNode(parseCode(text));
1408
+ break;
1409
+ case "Admonition":
1410
+ doc.appendNode(parseAdmonition(parts));
1411
+ break;
1412
+ case "Comment":
1413
+ skipComment();
1414
+ break;
1415
+ case "!!section":
1416
+ doc.appendNode(parseSection(text));
1417
+ break;
1418
+ case "!!header":
1419
+ parseHeaderFooter("header", text);
1420
+ break;
1421
+ case "!!footer":
1422
+ parseHeaderFooter("footer", text);
1423
+ break;
1424
+ case "!!rule":
1425
+ apllyRule(text);
1426
+ break;
1427
+ case "---":
1428
+ doc.appendNode({ type: "pageBreak", sourceLine: lineI });
1429
+ break;
1430
+ case "":
1431
+ case " ":
1432
+ const last = doc.nodes.at(-1);
1433
+ if (line.trim() != "" && last?.type == "text") {
1434
+ if (last.text == "") last.sourceLine = lineI;
1435
+ else last.text += "\n";
1436
+ last.text += line.trim();
1437
+ } else doc.appendText(line.trim(), lineI);
1438
+ break;
1439
+ default:
1440
+ prefix;
1441
+ throw new Error("switch default");
1442
+ }
1443
+ } catch (error) {
1444
+ const message = error instanceof Error ? error.message : String(error);
1445
+ throw new Error(`Line ${lineI}: ${message}`, { cause: error });
520
1446
  }
521
1447
  }
1448
+ doc.nodes.forEach((node) => {
1449
+ if (node.type == "admonition" && node.title == "\n")
1450
+ node.title = doc.admonition[node.admonitionType].title;
1451
+ });
522
1452
  doc.nodes = doc.nodes.filter((n) => n.type != "text" || n.text != "");
523
- findDocs(doc.nodes, logwarn);
1453
+ await findDocs(doc.nodes, warnAt);
1454
+ findMath(doc.nodes, warnAt);
524
1455
  findTables(doc.nodes);
525
- findPageBreaks(doc.nodes);
526
1456
  return doc;
527
1457
  }
528
1458
  function parseLine(line) {
@@ -539,7 +1469,7 @@ function parseLine(line) {
539
1469
  const text = splited.slice(1).join(" ");
540
1470
  let parts = [];
541
1471
  if (prefix.startsWith("!")) {
542
- const m_img = /!\[(.*)\]\((.*)\)({(.*)})?/.exec(line);
1472
+ const m_img = /^!\[(.*)\]\((.*)\)({(.*)})?/.exec(line);
543
1473
  if (m_img) return {
544
1474
  prefix: "Img",
545
1475
  text: line.trim(),
@@ -559,29 +1489,37 @@ function parseLine(line) {
559
1489
  }
560
1490
  }
561
1491
  if (prefix.startsWith("```")) return { prefix: "Code", text: line.trim().slice(3), level, parts };
1492
+ const m_admonition = /^(:{3,})(note|info|tip|warning|danger)(?:\[([^\]]*)\])?(?:\{([^}]*)\})?\s*$/i.exec(line.trim());
1493
+ if (m_admonition) return {
1494
+ prefix: "Admonition",
1495
+ text: "",
1496
+ level,
1497
+ parts: [m_admonition[1], m_admonition[2].toLowerCase(), m_admonition[3] ?? "\n", m_admonition[4] || ""]
1498
+ };
562
1499
  if (prefix.startsWith("<!--")) return { prefix: "Comment", text: line.trim().slice("<!--".length).trim(), level, parts };
563
- if (["#", "##", "###", "####", "#####", "######", "*", "1)", "!!section", "!!rule"].includes(prefix))
1500
+ if (["#", "##", "###", "####", "#####", "######", "*", "1)", "!!section", "!!header", "!!footer", "!!rule"].includes(prefix))
564
1501
  return { prefix, text, level: 0, parts };
565
1502
  return { prefix: "", text: line.trim(), level, parts };
566
1503
  }
567
- function findDocs(nodes, logwarn = console.warn) {
1504
+ async function findDocs(nodes, warnAt) {
1505
+ const { default: JSONC } = await import("jsonc-simple-parser");
568
1506
  const re_doc = /^!!\(([^{}]*)\)\s*{(.*)}$/s;
569
- const re_remTrailingComma = /,(\s*[}\]])/g;
570
1507
  for (let i = 0; i < nodes.length; i++) {
571
1508
  const node = nodes[i];
572
1509
  if (node.type != "text") continue;
573
- const m_doc = re_doc.exec(node.text.trimEnd().replaceAll(re_remTrailingComma, "$1"));
1510
+ const m_doc = re_doc.exec(node.text.trimEnd());
574
1511
  if (!m_doc) continue;
575
1512
  let dict = {};
576
1513
  try {
577
- dict = JSON.parse(`{${m_doc[2]}}`);
1514
+ dict = JSONC.parse(`{${m_doc[2]}}`);
578
1515
  } catch {
579
- logwarn(`Cant parse doc dict: {${m_doc[2].replaceAll("\n", " ")}}`);
1516
+ warnAt(node.sourceLine ?? -1, `Cant parse doc dict: {${m_doc[2].replaceAll("\n", " ")}}`);
580
1517
  }
581
1518
  nodes.splice(i, 1, {
582
1519
  type: "externalDoc",
583
1520
  path: trimEnd(trimStart(m_doc[1], "<", '"'), ">", '"'),
584
- dict: stringifyDict(dict)
1521
+ dict: stringifyDict(dict),
1522
+ sourceLine: node.sourceLine
585
1523
  });
586
1524
  }
587
1525
  }
@@ -605,7 +1543,7 @@ function stringifyDict(dict) {
605
1543
  }
606
1544
  return r;
607
1545
  }
608
- function findTables(nodes) {
1546
+ function findTables(nodes, hasHeader = true) {
609
1547
  const re_sep = /^(\s*:?-+:?\s*(?<!\\)\|)+\s*:?-+:?\s*$/;
610
1548
  const re_sep_oneCol = /^\|\s*:?-+:?\s*\|$/;
611
1549
  const trim = (line) => {
@@ -620,19 +1558,20 @@ function findTables(nodes) {
620
1558
  const lines = node.text.split("\n");
621
1559
  const offset = lines[0].includes("|") ? 0 : 1;
622
1560
  if (lines.length < 2 + offset) continue;
623
- const sep = trim(lines[1 + offset]);
624
- if (!re_sep.test(sep) && !re_sep_oneCol.test(lines[1 + offset])) continue;
625
- const cols = sep.split("|");
1561
+ const sep2 = trim(lines[1 + offset]);
1562
+ if (!re_sep.test(sep2) && !re_sep_oneCol.test(lines[1 + offset])) continue;
1563
+ const cols = sep2.split("|");
626
1564
  const header = trim(lines[offset]).split(/(?<!\\)\|/).map((v) => v.trim());
627
1565
  if (header.length != cols.length) continue;
628
1566
  const align = cols.map((v) => v.trim()).map((v) => v.startsWith(":") && v.endsWith(":") ? "c" : v.endsWith(":") ? "r" : "l");
629
- const rows = [tableRow(...header)];
1567
+ let sourceLine = node.sourceLine + offset;
1568
+ const rows = [tableRow(sourceLine++, ...header)];
630
1569
  for (const line of lines.slice(2 + offset)) {
631
1570
  const row = trim(line).split(/(?<!\\)\|/).map((v) => v.trim());
632
1571
  while (row.length < cols.length) row.push("");
633
- rows.push(tableRow(...row));
1572
+ rows.push(tableRow(++sourceLine, ...row));
634
1573
  }
635
- const table = { type: "table", align, rows };
1574
+ const table = { type: "table", align, rows, sourceLine: node.sourceLine, ...hasHeader ? {} : { header: false } };
636
1575
  nodes.splice(i, 1, table);
637
1576
  const prev = nodes[i - 1];
638
1577
  if (offset > 0) {
@@ -644,43 +1583,133 @@ function findTables(nodes) {
644
1583
  }
645
1584
  }
646
1585
  }
647
- function findPageBreaks(nodes) {
648
- const re_sep = /^\s*---+\s*$/;
1586
+ function findMath(nodes, warnAt) {
649
1587
  for (let i = 0; i < nodes.length; i++) {
650
1588
  const node = nodes[i];
651
- if (node.type != "text") continue;
652
- if (!node.text.includes("---")) continue;
1589
+ if (node?.type != "text") continue;
653
1590
  const lines = node.text.split("\n");
654
- const newNodes = [];
655
- for (const line of lines) {
656
- if (re_sep.test(line)) newNodes.push({ type: "pageBreak" });
657
- else {
658
- const last = newNodes.at(-1);
659
- if (last?.type == "text") last.text += "\n" + line;
660
- else newNodes.push({ type: "text", text: line, noIndent: node.noIndent, noMargin: node.noMargin });
1591
+ const replacement = [];
1592
+ let text = [];
1593
+ let textStart = 0;
1594
+ const flush = () => {
1595
+ if (text.length)
1596
+ replacement.push({ type: "text", text: text.join("\n"), sourceLine: (node.sourceLine ?? 0) + textStart });
1597
+ text = [];
1598
+ };
1599
+ for (let line = 0; line < lines.length; line++) {
1600
+ if (lines[line]?.trim() != "$$") {
1601
+ if (!text.length) textStart = line;
1602
+ text.push(lines[line]);
1603
+ continue;
661
1604
  }
1605
+ const start = line;
1606
+ let end = line + 1;
1607
+ while (end < lines.length && lines[end]?.trim() != "$$") end++;
1608
+ if (end >= lines.length) {
1609
+ warnAt((node.sourceLine ?? 0) + start, "Formula is not closed");
1610
+ if (!text.length) textStart = line;
1611
+ text.push(lines[line]);
1612
+ continue;
1613
+ }
1614
+ let id;
1615
+ let manualNumber;
1616
+ const idMatch = /^\s*(\[[a-zA-Zа-яА-ЯёЁ_\d#]+\])\s*$/.exec(text.at(-1) || "");
1617
+ const numberMatch = /^\s*(\(.*\))\s*$/.exec(text.at(-1) || "");
1618
+ if (idMatch) {
1619
+ id = `(${idMatch[1]})`;
1620
+ text.pop();
1621
+ } else if (numberMatch) {
1622
+ manualNumber = numberMatch[1];
1623
+ text.pop();
1624
+ }
1625
+ flush();
1626
+ replacement.push({
1627
+ type: "math",
1628
+ latex: lines.slice(start + 1, end).join("\n").trim(),
1629
+ title: id ?? manualNumber,
1630
+ sourceLine: (node.sourceLine ?? 0) + start
1631
+ });
1632
+ line = end;
1633
+ textStart = end + 1;
1634
+ }
1635
+ flush();
1636
+ if (replacement.some((n) => n.type == "math")) {
1637
+ nodes.splice(i, 1, ...replacement);
1638
+ i += replacement.length - 1;
662
1639
  }
663
- nodes.splice(i, 1, ...newNodes);
664
- i += newNodes.length - 1;
665
1640
  }
666
1641
  }
667
1642
  function runifyDoc(doc) {
668
1643
  function runifyNode(node) {
669
- if ("text" in node && node.text)
1644
+ if ("text" in node && node.text !== void 0)
670
1645
  node.text = runifyText(node.text, doc.rainbow);
671
- if ("title" in node && node.title)
1646
+ if ("title" in node && node.title !== void 0)
672
1647
  node.title = runifyText(node.title, doc.rainbow);
673
1648
  if (node.type == "table")
674
1649
  node.rows.forEach((row) => row.forEach(runifyNode));
675
1650
  if (node.type == "list")
676
1651
  node.items.forEach(runifyNode);
1652
+ if (node.type == "sectionBreak") {
1653
+ runifyHeaderFooter(node.header);
1654
+ runifyHeaderFooter(node.footer);
1655
+ }
677
1656
  }
678
1657
  doc.nodes.forEach(runifyNode);
1658
+ runifyHeaderFooter(doc.header);
1659
+ runifyHeaderFooter(doc.footer);
679
1660
  return doc;
1661
+ function runifyHeaderFooter(value) {
1662
+ if (value?.type != "content") return;
1663
+ value.nodes.forEach(runifyNode);
1664
+ }
680
1665
  }
681
1666
  var rainbowI = 0;
682
1667
  function runifyText(text, rainbow = false) {
683
- return replaceAmpCodes(text).replaceAll("\n", "&Tab;\n").replaceAll(/\s*<br>\s*/g, "\n").replaceAll("\u2014", "-").replaceAll(" - ", " \u2013 ").replaceAll(/(?<=[\p{L}\p{N}])-(?=[\p{L}\p{N}])/gu, "\u2011").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("*", "&Star;")).split(/(\[[^\]]*\]\([^)]*\))/g).map((p) => {
1668
+ const formulas = [];
1669
+ const codeSpans = [];
1670
+ function findClosingBackticks(from, count) {
1671
+ for (let i = from; i < text.length; ) {
1672
+ const start = text.indexOf("`", i);
1673
+ if (start < 0) return -1;
1674
+ let end = start + 1;
1675
+ while (text[end] == "`") end++;
1676
+ if (end - start == count) return start;
1677
+ i = end;
1678
+ }
1679
+ return -1;
1680
+ }
1681
+ ;
1682
+ let preprocessedText = "";
1683
+ for (let i = 0; i < text.length; ) {
1684
+ if (text[i] == "`") {
1685
+ let delimiterEnd = i + 1;
1686
+ while (text[delimiterEnd] == "`") delimiterEnd++;
1687
+ const delimiterLength = delimiterEnd - i;
1688
+ const end = findClosingBackticks(delimiterEnd, delimiterLength);
1689
+ if (end >= 0) {
1690
+ codeSpans.push(text.slice(delimiterEnd, end));
1691
+ preprocessedText += `\uE002${codeSpans.length - 1}\uE003`;
1692
+ i = end + delimiterLength;
1693
+ continue;
1694
+ }
1695
+ preprocessedText += text.slice(i, delimiterEnd);
1696
+ i = delimiterEnd;
1697
+ continue;
1698
+ }
1699
+ if (text[i] == "$" && text[i - 1] != "\\" && text[i + 1] != "$") {
1700
+ let end = i + 1;
1701
+ while (end < text.length && text[end] != "\n" && (text[end] != "$" || text[end - 1] == "\\")) end++;
1702
+ if (end < text.length && text[end] == "$") {
1703
+ formulas.push(text.slice(i + 1, end));
1704
+ preprocessedText += `\uE000${formulas.length - 1}\uE001`;
1705
+ i = end + 1;
1706
+ continue;
1707
+ }
1708
+ }
1709
+ preprocessedText += text[i++];
1710
+ }
1711
+ text = preprocessedText.replaceAll("\\$", "$");
1712
+ return replaceAmpCodes(text).replaceAll("\n", "&Tab;\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("*", "&Star;")).split(/(\[[^\]]*\]\([^)]*\))/g).map((p) => {
684
1713
  const m = /\[([^\]]*)\]\(([^)]*)\)/.exec(p);
685
1714
  if (!m) return { text: p };
686
1715
  return { text: m[1], link: m[2] };
@@ -706,17 +1735,23 @@ function runifyText(text, rainbow = false) {
706
1735
  link: rune.link,
707
1736
  bold: rune.bold,
708
1737
  italic: i % 2 == 1 && i != arr.length - 1 || rune.italic
709
- }))).flat().map((rune) => rune.text.split("```").map((p, i, arr) => ({
710
- ...rune,
711
- text: p,
712
- linebreak: i == 0 && rune.linebreak,
713
- mono: i % 2 == 1 && i != arr.length - 1
714
- }))).flat().map((rune) => rune.mono ? rune : rune.text.split("`").map((p, i, arr) => ({
715
- ...rune,
716
- text: p,
717
- linebreak: i == 0 && rune.linebreak,
718
- mono: i % 2 == 1 && i != arr.length - 1
719
- }))).flat().map((rune) => rune.link ? [rune] : rune.text.split(/(\[!?[a-zA-Zа-яА-ЯёЁ_\d#]+\s*[+-]?\s*\d*\])/g).map((p, i) => {
1738
+ }))).flat().map((rune) => rune.text.split(/(\uE002\d+\uE003)/).map((p, i) => {
1739
+ const m = /^\uE002(\d+)\uE003$/.exec(p);
1740
+ return {
1741
+ ...rune,
1742
+ text: m ? codeSpans[parseInt(m[1])] : p,
1743
+ mono: m ? true : rune.mono,
1744
+ linebreak: i == 0 && rune.linebreak
1745
+ };
1746
+ })).flat().map((rune) => rune.mono ? [rune] : rune.text.split(/(\uE000\d+\uE001)/).map((p, i) => {
1747
+ const m = /^\uE000(\d+)\uE001$/.exec(p);
1748
+ return {
1749
+ ...rune,
1750
+ text: m ? formulas[parseInt(m[1])] : p,
1751
+ type: m ? "math" : rune.type,
1752
+ linebreak: i == 0 && rune.linebreak
1753
+ };
1754
+ })).flat().map((rune) => rune.link || rune.mono ? [rune] : rune.text.split(/(\[!?[a-zA-Zа-яА-ЯёЁ_\d#]+\s*[+-]?\s*\d*\])/g).map((p, i) => {
720
1755
  const m = /\[(!?([a-zA-Zа-яА-ЯёЁ_\d]+|#)(\s*[-+]\s*\d+)?)\]/.exec(p);
721
1756
  const v = m && m[1];
722
1757
  const isVal = v?.at(0) == "!";
@@ -726,12 +1761,14 @@ function runifyText(text, rainbow = false) {
726
1761
  type: v ? isVal ? "val" : "ref" : rune.type,
727
1762
  linebreak: i == 0 && rune.linebreak
728
1763
  };
729
- })).flat().map((rune) => ({
1764
+ })).flat().map((rune, i, arr) => ({
730
1765
  ...rune,
731
1766
  ...!rune.type || rune.type == "text" ? {
732
- text: rune.text.replaceAll("&Star;", "*").replaceAll("&#x200B;", "")
1767
+ text: formatTypography(
1768
+ arr[i + 1]?.type == "ref" || arr[i + 1]?.type == "val" ? rune.text.replace(/[ \t]+$/, NBSP) : rune.text
1769
+ ).replaceAll("&Star;", "*").replaceAll("&#x200B;", "")
733
1770
  } : {}
734
- })).map((rune) => !rainbow || rune.type && rune.type != "text" ? [rune] : rune.text.split("").map((p, i) => ({
1771
+ })).map((rune) => !rainbow || rune.mono || rune.type && rune.type != "text" ? [rune] : rune.text.split("").map((p, i) => ({
735
1772
  ...rune,
736
1773
  text: p,
737
1774
  linebreak: i == 0 && rune.linebreak,
@@ -741,6 +1778,7 @@ function runifyText(text, rainbow = false) {
741
1778
  function replaceAmpCodes(text) {
742
1779
  const codes = {
743
1780
  "&#124;": "|",
1781
+ "&amp;": "&",
744
1782
  "&shy;": "\xAD",
745
1783
  "&laquo;": "\xAB",
746
1784
  "&raquo;": "\xBB",
@@ -812,95 +1850,621 @@ function replaceAmpCodes(text) {
812
1850
  }
813
1851
  return text;
814
1852
  }
1853
+ var NBSP = "\xA0";
1854
+ var NON_BREAKING_HYPHEN = "\u2011";
1855
+ var shortWords = ["\u0430", "\u0432", "\u0432\u043E", "\u0438", "\u043A", "\u043A\u043E", "\u043E", "\u043E\u0431", "\u043E\u0442", "\u0441", "\u0441\u043E", "\u0443", "\u0431\u0435\u0437", "\u0434\u043E", "\u0437\u0430", "\u0438\u0437", "\u043D\u0430", "\u043D\u0435", "\u043F\u043E", "\u043F\u043E\u0434", "\u043F\u0440\u0438", "\u043F\u0440\u043E", "\u0434\u043B\u044F"];
1856
+ var referenceTerms = [
1857
+ "\u0440\u0438\u0441\u0443\u043D\u043E\u043A",
1858
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u0430",
1859
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u0435",
1860
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u0443",
1861
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u043E\u043C",
1862
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u0438",
1863
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u043E\u0432",
1864
+ "\u0440\u0438\u0441\u0443\u043D\u043A\u0430\u0445",
1865
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0430",
1866
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u044B",
1867
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0435",
1868
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0443",
1869
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0435\u0439",
1870
+ "\u0442\u0430\u0431\u043B\u0438\u0446",
1871
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0430\u0445",
1872
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433",
1873
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0430",
1874
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0435",
1875
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0443",
1876
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u043E\u043C",
1877
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0438",
1878
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u043E\u0432",
1879
+ "\u043B\u0438\u0441\u0442\u0438\u043D\u0433\u0430\u0445",
1880
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u0430",
1881
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u044B",
1882
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u0435",
1883
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u0443",
1884
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u043E\u0439",
1885
+ "\u0444\u043E\u0440\u043C\u0443\u043B",
1886
+ "\u0444\u043E\u0440\u043C\u0443\u043B\u0430\u0445",
1887
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u0435",
1888
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u044F",
1889
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u0438",
1890
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u044E",
1891
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u0435\u043C",
1892
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u0439",
1893
+ "\u0443\u0440\u0430\u0432\u043D\u0435\u043D\u0438\u044F\u0445",
1894
+ "\u0440\u0430\u0437\u0434\u0435\u043B",
1895
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u0430",
1896
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u0435",
1897
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u0443",
1898
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u043E\u043C",
1899
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u044B",
1900
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u043E\u0432",
1901
+ "\u0440\u0430\u0437\u0434\u0435\u043B\u0430\u0445",
1902
+ "\u0433\u043B\u0430\u0432\u0430",
1903
+ "\u0433\u043B\u0430\u0432\u044B",
1904
+ "\u0433\u043B\u0430\u0432\u0435",
1905
+ "\u0433\u043B\u0430\u0432\u0443",
1906
+ "\u0433\u043B\u0430\u0432\u043E\u0439",
1907
+ "\u0433\u043B\u0430\u0432",
1908
+ "\u0433\u043B\u0430\u0432\u0430\u0445",
1909
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435",
1910
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F",
1911
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438",
1912
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044E",
1913
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u043C",
1914
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0439",
1915
+ "\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u0445",
1916
+ "\u043F\u0440\u0438\u043C\u0435\u0440",
1917
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u0430",
1918
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u0435",
1919
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u0443",
1920
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u043E\u043C",
1921
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u044B",
1922
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u043E\u0432",
1923
+ "\u043F\u0440\u0438\u043C\u0435\u0440\u0430\u0445",
1924
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C",
1925
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u0430",
1926
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u0435",
1927
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u0443",
1928
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u043E\u043C",
1929
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u044B",
1930
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u043E\u0432",
1931
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C\u0430\u0445",
1932
+ "\u0441\u0445\u0435\u043C\u0430",
1933
+ "\u0441\u0445\u0435\u043C\u044B",
1934
+ "\u0441\u0445\u0435\u043C\u0435",
1935
+ "\u0441\u0445\u0435\u043C\u0443",
1936
+ "\u0441\u0445\u0435\u043C\u043E\u0439",
1937
+ "\u0441\u0445\u0435\u043C",
1938
+ "\u0441\u0445\u0435\u043C\u0430\u0445"
1939
+ ];
1940
+ var referenceAbbreviations = ["\u0440\u0438\u0441", "\u0442\u0430\u0431\u043B", "\u043B\u0438\u0441\u0442", "\u0444\u043E\u0440\u043C", "\u0443\u0440", "\u0440\u0430\u0437\u0434", "\u0433\u043B", "\u043F\u0440\u0438\u043B"];
1941
+ var units = ["%", "\xB0C", "\xB0F", "\u043C\u043C", "\u0441\u043C", "\u0434\u043C", "\u043A\u043C", "\u043C\u043A\u043C", "\u043D\u043C", "\u043C", "\u043C\u0433", "\u043A\u0433", "\u0433", "\u043C\u043B", "\u043B", "\u043C\u0441", "\u043C\u043A\u0441", "\u043D\u0441", "\u0441", "\u043C\u0438\u043D", "\u0447", "\u0413\u0446", "\u043A\u0413\u0446", "\u041C\u0413\u0446", "\u0413\u0413\u0446", "\u0412\u0442", "\u043A\u0412\u0442", "\u041C\u0412\u0442", "\u0412", "\u043A\u0412", "\u0410", "\u043C\u0410", "\u041E\u043C", "\u043A\u041E\u043C", "\u041C\u041E\u043C", "\u0411", "\u041A\u0411", "\u041C\u0411", "\u0413\u0411", "\u0422\u0411", "\u0431\u0438\u0442", "\u041A\u0431\u0438\u0442", "\u041C\u0431\u0438\u0442", "\u0413\u0431\u0438\u0442", "\u0431\u0438\u0442/\u0441", "\u041A\u0431\u0438\u0442/\u0441", "\u041C\u0431\u0438\u0442/\u0441", "\u0413\u0431\u0438\u0442/\u0441"];
1942
+ function escapeRegExp(value) {
1943
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1944
+ }
1945
+ function createAlternation(values) {
1946
+ return [...values].sort((a, b) => b.length - a.length).map(escapeRegExp).join("|");
1947
+ }
1948
+ var shortWordsPattern = createAlternation(shortWords);
1949
+ var referenceTermsPattern = createAlternation(referenceTerms);
1950
+ var referenceAbbreviationsPattern = createAlternation(referenceAbbreviations);
1951
+ var unitsPattern = createAlternation(units);
1952
+ var referenceIdentifierPattern = String.raw`(?:\(\s*\d+(?:\.\d+)*\s*\)|\d+(?:\.\d+)*|[А-ЯЁA-Z](?:[^\p{L}]|$))`;
1953
+ function formatTypography(text) {
1954
+ return text.replace(
1955
+ new RegExp(`(^|[^\\p{L}\\p{N}_])(${shortWordsPattern})[ \\t]+(?=\\S)`, "giu"),
1956
+ (_, prefix, word) => `${prefix}${word}${NBSP}`
1957
+ ).replace(
1958
+ new RegExp(`(^|[^\\p{L}\\p{N}_])(${referenceTermsPattern})[ \\t]+(?=${referenceIdentifierPattern})`, "giu"),
1959
+ (_, prefix, term) => `${prefix}${term}${NBSP}`
1960
+ ).replace(
1961
+ new RegExp(`(^|[^\\p{L}\\p{N}_])(${referenceAbbreviationsPattern})\\.[ \\t]+(?=${referenceIdentifierPattern})`, "giu"),
1962
+ (_, prefix, abbreviation) => `${prefix}${abbreviation}.${NBSP}`
1963
+ ).replace(/\b(п|пп|ч|ст|с|стр|абз)\.[ \t]+(?=\d)/giu, `$1.${NBSP}`).replace(/№[ \t]+(?=\d)/gu, `\u2116${NBSP}`).replace(/(§§?)[ \t]+(?=\d)/gu, `$1${NBSP}`).replace(/\b(ГОСТ)[ \t]+(?=Р(?:[ \t]+\d)|\d)/giu, `$1${NBSP}`).replace(
1964
+ /\b(ГОСТ\u00A0Р|ГОСТ Р)[ \t]+(?=\d)/giu,
1965
+ (_, standard) => `${standard.replace(" ", NBSP)}${NBSP}`
1966
+ ).replace(/\b(ISO|IEC|IEEE|RFC|DIN|EN)[ \t]+(?=\d)/g, `$1${NBSP}`).replace(/\b(г|ул|пр|просп|пер|бул|наб|пл|д|корп|стр|кв)\.[ \t]+(?=\S)/giu, `$1.${NBSP}`).replace(/(\d{4})[ \t]+(?=гг?\.)/gu, `$1${NBSP}`).replace(/([А-ЯЁA-Z])\.[ \t]+([А-ЯЁA-Z])\.[ \t]+(?=[А-ЯЁA-Z][\p{L}-]+)/gu, `$1.${NBSP}$2.${NBSP}`).replace(/([А-ЯЁA-Z])\.[ \t]+(?=[А-ЯЁA-Z][\p{L}-]+)/gu, `$1.${NBSP}`).replace(new RegExp(`(\\d)[ \\t]+(?=(?:${unitsPattern})(?=$|[^\\p{L}]))`, "giu"), `$1${NBSP}`).replaceAll(/(?<=[\p{L}\p{N}])-(?=[\p{L}\p{N}])/gu, NON_BREAKING_HYPHEN);
1967
+ }
815
1968
 
816
1969
  // src/serializer.ts
817
- var fs3 = __toESM(require("fs"));
818
- var import_docx = require("docx");
1970
+ var fs4 = __toESM(require("fs"));
1971
+ var import_docx2 = require("docx");
819
1972
  var import_image_size = require("image-size");
820
- var import_path2 = __toESM(require("path"));
821
- var import_prismjs = __toESM(require("prismjs"));
822
- var import_prism_clike = require("prismjs/components/prism-clike");
823
- var import_prism_markup = require("prismjs/components/prism-markup");
824
- var import_prism_css = require("prismjs/components/prism-css");
825
- var import_prism_javascript = require("prismjs/components/prism-javascript");
826
- var import_prism_typescript = require("prismjs/components/prism-typescript");
827
- var import_prism_jsx = require("prismjs/components/prism-jsx");
828
- var import_prism_tsx = require("prismjs/components/prism-tsx");
829
- var import_prism_json = require("prismjs/components/prism-json");
830
- var import_prism_bash = require("prismjs/components/prism-bash");
831
- var import_prism_powershell = require("prismjs/components/prism-powershell");
832
- var import_prism_python = require("prismjs/components/prism-python");
833
- var import_prism_java = require("prismjs/components/prism-java");
834
- var import_prism_c = require("prismjs/components/prism-c");
835
- var import_prism_cpp = require("prismjs/components/prism-cpp");
836
- var import_prism_csharp = require("prismjs/components/prism-csharp");
837
- var import_prism_go = require("prismjs/components/prism-go");
838
- var import_prism_rust = require("prismjs/components/prism-rust");
839
- var import_prism_php = require("prismjs/components/prism-php");
840
- var import_prism_ruby = require("prismjs/components/prism-ruby");
841
- var import_prism_swift = require("prismjs/components/prism-swift");
842
- var import_prism_kotlin = require("prismjs/components/prism-kotlin");
843
- var import_prism_sql = require("prismjs/components/prism-sql");
844
- var import_prism_yaml = require("prismjs/components/prism-yaml");
845
- var import_prism_markdown = require("prismjs/components/prism-markdown");
846
- var import_prism_docker = require("prismjs/components/prism-docker");
847
- var import_prism_nginx = require("prismjs/components/prism-nginx");
1973
+ var import_path3 = __toESM(require("path"));
848
1974
 
849
- // src/errors.ts
850
- var UserInputError = class extends Error {
851
- constructor(message) {
852
- super(message);
1975
+ // src/math.ts
1976
+ var import_docx = require("docx");
1977
+ var Omml = class extends import_docx.XmlComponent {
1978
+ constructor(tag, children = [], attributes = {}) {
1979
+ super(tag);
1980
+ if (Object.keys(attributes).length) this.root.push({ _attr: attributes });
1981
+ this.root.push(...children);
1982
+ }
1983
+ };
1984
+ var symbols = {
1985
+ alpha: "\u03B1",
1986
+ beta: "\u03B2",
1987
+ gamma: "\u03B3",
1988
+ delta: "\u03B4",
1989
+ epsilon: "\u03B5",
1990
+ varepsilon: "\u03B5",
1991
+ zeta: "\u03B6",
1992
+ eta: "\u03B7",
1993
+ theta: "\u03B8",
1994
+ vartheta: "\u03D1",
1995
+ iota: "\u03B9",
1996
+ kappa: "\u03BA",
1997
+ lambda: "\u03BB",
1998
+ mu: "\u03BC",
1999
+ nu: "\u03BD",
2000
+ xi: "\u03BE",
2001
+ pi: "\u03C0",
2002
+ rho: "\u03C1",
2003
+ sigma: "\u03C3",
2004
+ tau: "\u03C4",
2005
+ upsilon: "\u03C5",
2006
+ phi: "\u03C6",
2007
+ varphi: "\u03D5",
2008
+ chi: "\u03C7",
2009
+ psi: "\u03C8",
2010
+ omega: "\u03C9",
2011
+ Gamma: "\u0393",
2012
+ Delta: "\u0394",
2013
+ Theta: "\u0398",
2014
+ Lambda: "\u039B",
2015
+ Xi: "\u039E",
2016
+ Pi: "\u03A0",
2017
+ Sigma: "\u03A3",
2018
+ Upsilon: "\u03A5",
2019
+ Phi: "\u03A6",
2020
+ Psi: "\u03A8",
2021
+ Omega: "\u03A9",
2022
+ cdot: "\xB7",
2023
+ times: "\xD7",
2024
+ div: "\xF7",
2025
+ pm: "\xB1",
2026
+ mp: "\u2213",
2027
+ ast: "\u2217",
2028
+ star: "\u22C6",
2029
+ circ: "\u2218",
2030
+ bullet: "\u2219",
2031
+ oplus: "\u2295",
2032
+ ominus: "\u2296",
2033
+ otimes: "\u2297",
2034
+ oslash: "\u2298",
2035
+ odot: "\u2299",
2036
+ setminus: "\u2216",
2037
+ wedge: "\u2227",
2038
+ vee: "\u2228",
2039
+ le: "\u2264",
2040
+ leq: "\u2264",
2041
+ ge: "\u2265",
2042
+ geq: "\u2265",
2043
+ neq: "\u2260",
2044
+ ne: "\u2260",
2045
+ approx: "\u2248",
2046
+ equiv: "\u2261",
2047
+ sim: "\u223C",
2048
+ simeq: "\u2243",
2049
+ cong: "\u2245",
2050
+ propto: "\u221D",
2051
+ ll: "\u226A",
2052
+ gg: "\u226B",
2053
+ infty: "\u221E",
2054
+ partial: "\u2202",
2055
+ nabla: "\u2207",
2056
+ in: "\u2208",
2057
+ notin: "\u2209",
2058
+ ni: "\u220B",
2059
+ subset: "\u2282",
2060
+ subseteq: "\u2286",
2061
+ superset: "\u2283",
2062
+ supseteq: "\u2287",
2063
+ emptyset: "\u2205",
2064
+ varnothing: "\u2205",
2065
+ cup: "\u222A",
2066
+ cap: "\u2229",
2067
+ perp: "\u22A5",
2068
+ parallel: "\u2225",
2069
+ mid: "\u2223",
2070
+ angle: "\u2220",
2071
+ therefore: "\u2234",
2072
+ because: "\u2235",
2073
+ to: "\u2192",
2074
+ rightarrow: "\u2192",
2075
+ leftarrow: "\u2190",
2076
+ leftrightarrow: "\u2194",
2077
+ mapsto: "\u21A6",
2078
+ Rightarrow: "\u21D2",
2079
+ Leftarrow: "\u21D0",
2080
+ Leftrightarrow: "\u21D4",
2081
+ uparrow: "\u2191",
2082
+ downarrow: "\u2193",
2083
+ updownarrow: "\u2195",
2084
+ forall: "\u2200",
2085
+ exists: "\u2203",
2086
+ neg: "\xAC",
2087
+ land: "\u2227",
2088
+ lor: "\u2228",
2089
+ degree: "\xB0",
2090
+ ell: "\u2113",
2091
+ prime: "\u2032",
2092
+ hbar: "\u210F",
2093
+ aleph: "\u2135",
2094
+ Re: "\u211C",
2095
+ Im: "\u2111",
2096
+ ldots: "\u2026",
2097
+ dots: "\u2026",
2098
+ cdots: "\u22EF",
2099
+ vdots: "\u22EE",
2100
+ ddots: "\u22F1"
2101
+ };
2102
+ var operators = { sin: "sin", cos: "cos", tan: "tan", cot: "cot", sec: "sec", csc: "csc", log: "log", ln: "ln", exp: "exp", max: "max", min: "min", gcd: "gcd", det: "det" };
2103
+ function run(text, style) {
2104
+ const value = style == "plain" ? "p" : style == "bold" ? "b" : style == "italic" ? "i" : void 0;
2105
+ return new Omml("m:r", [
2106
+ ...style == "double-struck" || style == "script" ? [new Omml("m:rPr", [new Omml("m:scr", [], { "m:val": style }), new Omml("m:sty", [], { "m:val": "p" })])] : [],
2107
+ ...value ? [new Omml("m:rPr", [new Omml("m:sty", [], { "m:val": value })])] : [],
2108
+ new Omml("m:t", [text], { "xml:space": "preserve" })
2109
+ ]);
2110
+ }
2111
+ function arg(children) {
2112
+ return new Omml("m:e", children);
2113
+ }
2114
+ function delimiter(children, begin, end) {
2115
+ return new Omml("m:d", [
2116
+ new Omml("m:dPr", [new Omml("m:begChr", [], { "m:val": begin }), new Omml("m:endChr", [], { "m:val": end })]),
2117
+ arg(children)
2118
+ ]);
2119
+ }
2120
+ function latexToOmml(latex, para = false) {
2121
+ const parser = new LatexParser(latex);
2122
+ const body = parser.sequence();
2123
+ if (!parser.done()) throw new Error(`unexpected "${parser.peek()}"`);
2124
+ const math = new Omml("m:oMath", body);
2125
+ return para ? new Omml("m:oMathPara", [math]) : math;
2126
+ }
2127
+ var LatexParser = class {
2128
+ constructor(source) {
2129
+ this.source = source;
2130
+ }
2131
+ source;
2132
+ i = 0;
2133
+ done() {
2134
+ return this.i >= this.source.length;
2135
+ }
2136
+ peek() {
2137
+ return this.source[this.i] || "";
2138
+ }
2139
+ take() {
2140
+ return this.source[this.i++] || "";
2141
+ }
2142
+ skipWhitespace() {
2143
+ while (/\s/.test(this.peek())) this.take();
2144
+ }
2145
+ command(name) {
2146
+ return this.source.slice(this.i).startsWith(`\\${name}`) && !/[A-Za-z]/.test(this.source[this.i + name.length + 1] || "");
2147
+ }
2148
+ sequence(stop, style, preserveWhitespace = false, boundary) {
2149
+ const result = [];
2150
+ while (!this.done() && this.peek() != stop && !boundary?.()) {
2151
+ if (/\s/.test(this.peek())) {
2152
+ this.take();
2153
+ if (preserveWhitespace) result.push(run(" ", style));
2154
+ continue;
2155
+ }
2156
+ if (this.command("displaystyle") || this.command("textstyle")) {
2157
+ this.take();
2158
+ while (/[A-Za-z]/.test(this.peek())) this.take();
2159
+ continue;
2160
+ }
2161
+ if (this.source.startsWith("\\!", this.i)) {
2162
+ this.i += 2;
2163
+ continue;
2164
+ }
2165
+ result.push(this.decoratedAtom(style, preserveWhitespace));
2166
+ }
2167
+ if (stop) {
2168
+ if (this.take() != stop) throw new Error(`missing "${stop}"`);
2169
+ }
2170
+ return result;
2171
+ }
2172
+ decoratedAtom(style, preserveWhitespace = false) {
2173
+ let value = this.atom(style, preserveWhitespace);
2174
+ let sub;
2175
+ let sup;
2176
+ while (true) {
2177
+ const beforeSpace = this.i;
2178
+ this.skipWhitespace();
2179
+ if (this.peek() != "_" && this.peek() != "^") {
2180
+ this.i = beforeSpace;
2181
+ break;
2182
+ }
2183
+ const marker = this.take();
2184
+ const script = this.groupOrAtom(style);
2185
+ if (marker == "_" ? sub : sup) throw new Error("duplicate script");
2186
+ if (marker == "_") sub = script;
2187
+ else sup = script;
2188
+ }
2189
+ if (sub && sup) value = new Omml("m:sSubSup", [new Omml("m:e", [value]), new Omml("m:sub", sub), new Omml("m:sup", sup)]);
2190
+ else if (sub) value = new Omml("m:sSub", [new Omml("m:e", [value]), new Omml("m:sub", sub)]);
2191
+ else if (sup) value = new Omml("m:sSup", [new Omml("m:e", [value]), new Omml("m:sup", sup)]);
2192
+ return value;
2193
+ }
2194
+ groupOrAtom(style, preserveWhitespace = false) {
2195
+ this.skipWhitespace();
2196
+ if (this.done() || ["}", "_", "^", "&"].includes(this.peek())) throw new Error("argument expected");
2197
+ if (this.peek() == "{") {
2198
+ this.take();
2199
+ return this.sequence("}", style, preserveWhitespace);
2200
+ }
2201
+ return [this.atom(style)];
2202
+ }
2203
+ atom(style, preserveWhitespace = false) {
2204
+ const ch = this.take();
2205
+ if (!ch || ["}", "_", "^", "&"].includes(ch)) throw new Error(`unexpected "${ch}"`);
2206
+ if (ch == "{") return new Omml("m:box", [arg(this.sequence("}", style, preserveWhitespace))]);
2207
+ if (ch != "\\") return run(ch, style);
2208
+ let name = "";
2209
+ while (/[A-Za-z]/.test(this.peek())) name += this.take();
2210
+ if (!name) {
2211
+ const escaped = this.take();
2212
+ if (!escaped) throw new Error("command expected");
2213
+ const spaces = { ",": "\u2009", ";": "\u2004", ":": "\u2005", " ": " " };
2214
+ if (spaces[escaped]) return run(spaces[escaped], style);
2215
+ if (escaped == "!") return run("", style);
2216
+ return run(escaped, style);
2217
+ }
2218
+ this.skipWhitespace();
2219
+ if (name == "frac" || name == "dfrac" || name == "tfrac") return new Omml("m:f", [new Omml("m:num", this.groupOrAtom(style)), new Omml("m:den", this.groupOrAtom(style))]);
2220
+ if (name == "sqrt") {
2221
+ let degree;
2222
+ if (this.peek() == "[") {
2223
+ this.take();
2224
+ degree = this.sequence("]", style);
2225
+ }
2226
+ return new Omml("m:rad", [new Omml("m:radPr", degree ? [] : [new Omml("m:degHide", [], { "m:val": "1" })]), new Omml("m:deg", degree || []), arg(this.groupOrAtom(style))]);
2227
+ }
2228
+ if (name == "text") return new Omml("m:box", [arg(this.groupOrAtom("plain", true))]);
2229
+ if (name == "mathrm" || name == "operatorname") return new Omml("m:box", [arg(this.groupOrAtom("plain"))]);
2230
+ if (name == "mathbf") return new Omml("m:box", [arg(this.groupOrAtom("bold"))]);
2231
+ if (name == "mathit") return new Omml("m:box", [arg(this.groupOrAtom("italic"))]);
2232
+ if (["mathbb", "mathcal"].includes(name)) return new Omml("m:box", [arg(this.groupOrAtom(name == "mathbb" ? "double-struck" : "script"))]);
2233
+ if (["hat", "widehat", "vec"].includes(name)) {
2234
+ const chr = name == "vec" ? "\u20D7" : "\u0302";
2235
+ return new Omml("m:acc", [new Omml("m:accPr", [new Omml("m:chr", [], { "m:val": chr })]), arg(this.groupOrAtom(style))]);
2236
+ }
2237
+ if (["overline", "bar", "underline"].includes(name)) {
2238
+ const pos = name == "underline" ? "bot" : "top";
2239
+ return new Omml("m:bar", [new Omml("m:barPr", [new Omml("m:pos", [], { "m:val": pos })]), arg(this.groupOrAtom(style))]);
2240
+ }
2241
+ if (name == "binom" || name == "dbinom") return delimiter([new Omml("m:f", [new Omml("m:fPr", [new Omml("m:type", [], { "m:val": "noBar" })]), new Omml("m:num", this.groupOrAtom(style)), new Omml("m:den", this.groupOrAtom(style))])], "(", ")");
2242
+ if (name == "lim") {
2243
+ let below = true;
2244
+ if (this.command("limits") || this.command("nolimits")) {
2245
+ below = this.command("limits");
2246
+ this.i += below ? 7 : 9;
2247
+ this.skipWhitespace();
2248
+ }
2249
+ let sub = [];
2250
+ if (this.peek() == "_") {
2251
+ this.take();
2252
+ sub = this.groupOrAtom(style);
2253
+ }
2254
+ if (!sub.length) return run("lim", "plain");
2255
+ return new Omml(below ? "m:limLow" : "m:sSub", [arg([run("lim", "plain")]), new Omml(below ? "m:lim" : "m:sub", sub)]);
2256
+ }
2257
+ if (["sum", "prod", "int", "iint", "iiint"].includes(name)) {
2258
+ const chr = name == "sum" ? "\u2211" : name == "prod" ? "\u220F" : name == "iint" ? "\u222C" : name == "iiint" ? "\u222D" : "\u222B";
2259
+ let sub = [], sup = [];
2260
+ let limitLocation;
2261
+ while (true) {
2262
+ this.skipWhitespace();
2263
+ if (this.command("limits") || this.command("nolimits")) {
2264
+ const limits = this.command("limits");
2265
+ this.i += limits ? 7 : 9;
2266
+ limitLocation = limits ? "undOvr" : "subSup";
2267
+ continue;
2268
+ }
2269
+ if (this.peek() != "_" && this.peek() != "^") break;
2270
+ const marker = this.take();
2271
+ const script = this.groupOrAtom(style);
2272
+ if (marker == "_" ? sub.length : sup.length) throw new Error("duplicate script");
2273
+ if (marker == "_") sub = script;
2274
+ else sup = script;
2275
+ this.skipWhitespace();
2276
+ }
2277
+ while (/\s/.test(this.peek())) this.take();
2278
+ const operand = this.done() || ["}", "]", ")", "&", "=", "<", ">"].includes(this.peek()) || this.command("right") || this.command("end") || this.source.startsWith("\\\\", this.i) ? [] : [this.decoratedAtom(style)];
2279
+ return new Omml("m:nary", [new Omml("m:naryPr", [
2280
+ new Omml("m:chr", [], { "m:val": chr }),
2281
+ ...limitLocation ? [new Omml("m:limLoc", [], { "m:val": limitLocation })] : [],
2282
+ new Omml("m:subHide", [], { "m:val": sub.length ? "0" : "1" }),
2283
+ new Omml("m:supHide", [], { "m:val": sup.length ? "0" : "1" })
2284
+ ]), new Omml("m:sub", sub), new Omml("m:sup", sup), arg(operand)]);
2285
+ }
2286
+ if (name == "left") {
2287
+ const begin = this.readDelimiter();
2288
+ const body = this.sequence(void 0, style, false, () => this.command("right"));
2289
+ if (!this.command("right")) throw new Error("missing \\right");
2290
+ this.i += 6;
2291
+ return delimiter(body, begin, this.readDelimiter());
2292
+ }
2293
+ if (name == "begin") return this.matrix(style);
2294
+ if (symbols[name]) return run(symbols[name], style);
2295
+ if (operators[name]) return run(operators[name], "plain");
2296
+ if (["quad", "qquad"].includes(name)) return run(name == "quad" ? "\u2003" : "\u2003\u2003", style);
2297
+ throw new Error(`unsupported command \\${name}`);
2298
+ }
2299
+ readDelimiter() {
2300
+ this.skipWhitespace();
2301
+ const ch = this.take();
2302
+ if (ch == ".") return "";
2303
+ if (ch && "()[]|{}".includes(ch)) return ch;
2304
+ if (ch == "\\") {
2305
+ let name = "";
2306
+ while (/[A-Za-z]/.test(this.peek())) name += this.take();
2307
+ if (!name) name = this.take();
2308
+ const delimiters = { "{": "{", "}": "}", "|": "\u2016", lbrace: "{", rbrace: "}", langle: "\u27E8", rangle: "\u27E9", lvert: "|", rvert: "|", vert: "|", lVert: "\u2016", rVert: "\u2016", Vert: "\u2016" };
2309
+ if (delimiters[name]) return delimiters[name];
2310
+ }
2311
+ throw new Error("delimiter expected");
2312
+ }
2313
+ matrix(style) {
2314
+ if (this.peek() != "{") throw new Error("environment name expected");
2315
+ this.take();
2316
+ let env = "";
2317
+ while (!this.done() && this.peek() != "}") env += this.take();
2318
+ this.take();
2319
+ if (!["matrix", "pmatrix", "bmatrix", "cases"].includes(env)) throw new Error(`unsupported environment ${env}`);
2320
+ const rows = [];
2321
+ let cells = [];
2322
+ while (true) {
2323
+ this.skipWhitespace();
2324
+ if (this.done()) throw new Error(`environment ${env} is not closed`);
2325
+ if (this.command("end")) {
2326
+ this.i += 4;
2327
+ this.skipWhitespace();
2328
+ const closing = `{${env}}`;
2329
+ if (!this.source.startsWith(closing, this.i)) throw new Error(`mismatched environment ${env}`);
2330
+ this.i += closing.length;
2331
+ if (cells.length) rows.push(new Omml("m:mr", cells));
2332
+ break;
2333
+ }
2334
+ cells.push(arg(this.sequence(void 0, style, false, () => this.peek() == "&" || this.source.startsWith("\\\\", this.i) || this.command("end"))));
2335
+ if (this.peek() == "&") {
2336
+ this.take();
2337
+ continue;
2338
+ }
2339
+ if (this.source.startsWith("\\\\", this.i)) {
2340
+ this.i += 2;
2341
+ rows.push(new Omml("m:mr", cells));
2342
+ cells = [];
2343
+ }
2344
+ }
2345
+ const matrix = new Omml("m:m", rows);
2346
+ if (env == "pmatrix") return delimiter([matrix], "(", ")");
2347
+ if (env == "bmatrix") return delimiter([matrix], "[", "]");
2348
+ if (env == "cases") return delimiter([matrix], "{", "");
2349
+ return matrix;
853
2350
  }
854
2351
  };
855
2352
 
856
2353
  // src/serializer.ts
2354
+ var import_prismjs = __toESM(require("prismjs"));
2355
+ var import_prism_clike = require("prismjs/components/prism-clike.js");
2356
+ var import_prism_markup = require("prismjs/components/prism-markup.js");
2357
+ var import_prism_css = require("prismjs/components/prism-css.js");
2358
+ var import_prism_javascript = require("prismjs/components/prism-javascript.js");
2359
+ var import_prism_typescript = require("prismjs/components/prism-typescript.js");
2360
+ var import_prism_jsx = require("prismjs/components/prism-jsx.js");
2361
+ var import_prism_tsx = require("prismjs/components/prism-tsx.js");
2362
+ var import_prism_json = require("prismjs/components/prism-json.js");
2363
+ var import_prism_bash = require("prismjs/components/prism-bash.js");
2364
+ var import_prism_powershell = require("prismjs/components/prism-powershell.js");
2365
+ var import_prism_python = require("prismjs/components/prism-python.js");
2366
+ var import_prism_java = require("prismjs/components/prism-java.js");
2367
+ var import_prism_c = require("prismjs/components/prism-c.js");
2368
+ var import_prism_cpp = require("prismjs/components/prism-cpp.js");
2369
+ var import_prism_csharp = require("prismjs/components/prism-csharp.js");
2370
+ var import_prism_go = require("prismjs/components/prism-go.js");
2371
+ var import_prism_rust = require("prismjs/components/prism-rust.js");
2372
+ var import_prism_php = require("prismjs/components/prism-php.js");
2373
+ var import_prism_ruby = require("prismjs/components/prism-ruby.js");
2374
+ var import_prism_swift = require("prismjs/components/prism-swift.js");
2375
+ var import_prism_kotlin = require("prismjs/components/prism-kotlin.js");
2376
+ var import_prism_sql = require("prismjs/components/prism-sql.js");
2377
+ var import_prism_yaml = require("prismjs/components/prism-yaml.js");
2378
+ var import_prism_markdown = require("prismjs/components/prism-markdown.js");
2379
+ var import_prism_docker = require("prismjs/components/prism-docker.js");
2380
+ var import_prism_nginx = require("prismjs/components/prism-nginx.js");
857
2381
  var STYLE_list = "afc";
858
2382
  var STYLE_table_title = "TableCaption";
859
2383
  var STYLE_code_title = "ListingCaption";
860
2384
  var STYLE_code = "ListingCode";
861
- async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath) {
862
- const allowedRealPath = checkFilesIsInsidePath === false ? false : realpathAllowMissing(checkFilesIsInsidePath === "" ? workdir : checkFilesIsInsidePath);
863
- const getPath = (fname) => {
864
- if (process.platform != "win32") fname = fname.replaceAll("\\", "/");
865
- if (process.platform == "win32" && fname.startsWith("/")) fname = "." + fname;
866
- const targetPath = import_path2.default.isAbsolute(fname) ? import_path2.default.resolve(fname) : import_path2.default.resolve(workdir, fname);
867
- if (allowedRealPath !== false) {
868
- const targetRealPath = realpathAllowMissing(targetPath);
869
- const relative = import_path2.default.relative(allowedRealPath, targetRealPath);
870
- const isOutside = relative === ".." || relative.startsWith(`..${import_path2.default.sep}`) || import_path2.default.isAbsolute(relative);
871
- if (isOutside) throw new UserInputError(`Access denied: "${fname}" resolves outside the working directory.`);
872
- }
873
- return targetPath;
874
- };
2385
+ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath, logwarn = console.warn) {
2386
+ const { resolvePath: getPath } = getSafePathResolver(workdir, checkFilesIsInsidePath);
875
2387
  const sections = [];
876
2388
  const numbering = [];
877
2389
  const docSections = (function splitSections() {
878
- const sections2 = [{ displayPageNum: true, orientation: "portrait", pageStart: 1, nodes: [] }];
2390
+ let header = doc.header;
2391
+ let footer = doc.footer;
2392
+ const sections2 = [{ displayPageNum: true, orientation: "portrait", pageStart: 1, header, footer, nodes: [] }];
879
2393
  for (let j = 0; j < doc.nodes.length; j++) {
880
2394
  const node = doc.nodes[j];
881
- if (node.type == "sectionBreak")
2395
+ if (node.type == "sectionBreak") {
2396
+ header = node.header ?? header;
2397
+ footer = node.footer ?? footer;
882
2398
  sections2.push({
883
- displayPageNum: node.pageStart == null ? sections2.at(-1)?.displayPageNum || true : node.pageStart >= 0,
2399
+ displayPageNum: node.pageStart == null ? sections2.at(-1)?.displayPageNum ?? true : node.pageStart >= 0,
884
2400
  orientation: node.orientation || sections2.at(-1)?.orientation || "portrait",
885
2401
  pageStart: node.pageStart,
2402
+ header,
2403
+ footer,
886
2404
  nodes: []
887
2405
  });
888
- else
2406
+ } else
889
2407
  sections2.at(-1)?.nodes.push(node);
890
2408
  }
891
2409
  return sections2.filter((s) => s.nodes.length > 0);
892
2410
  })();
893
2411
  for (const section of docSections) {
894
- let renderNode2 = function(node, prevChild, prevNode) {
2412
+ let renderHeaderFooter2 = function(value, isFooter) {
2413
+ if (value.type == "none") return void 0;
2414
+ if (value.type == "auto") {
2415
+ if (!isFooter) return void 0;
2416
+ return new import_docx2.Footer({
2417
+ children: [new import_docx2.Paragraph({
2418
+ alignment: import_docx2.AlignmentType.CENTER,
2419
+ children: [new import_docx2.TextRun({ children: section.displayPageNum ? [import_docx2.PageNumber.CURRENT] : [] })],
2420
+ indent: { firstLine: 0 },
2421
+ spacing: { after: 0, line: 240 }
2422
+ })]
2423
+ });
2424
+ }
2425
+ const contentValue = value;
2426
+ const content = contentValue.nodes.flatMap((node) => {
2427
+ if (node.type == "text") return [new import_docx2.Paragraph({
2428
+ children: renderText(node.text, node.sourceLine),
2429
+ alignment: contentValue.align,
2430
+ indent: { firstLine: 0 },
2431
+ spacing: isFooter ? { after: 0, line: 240 } : { line: 240 }
2432
+ })];
2433
+ return [renderHeaderFooterTable2(node)];
2434
+ });
2435
+ return isFooter ? new import_docx2.Footer({ children: content }) : new import_docx2.Header({ children: content });
2436
+ }, renderHeaderFooterTable2 = function(node) {
2437
+ return new import_docx2.Table({
2438
+ width: { type: "dxa", size: (0, import_docx2.convertMillimetersToTwip)(section.orientation == "landscape" ? 255.8 : 168.8) },
2439
+ borders: {
2440
+ top: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" },
2441
+ bottom: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" },
2442
+ left: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" },
2443
+ right: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" },
2444
+ insideHorizontal: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" },
2445
+ insideVertical: { style: import_docx2.BorderStyle.SINGLE, size: 4, color: "808080" }
2446
+ },
2447
+ rows: node.rows.map((row) => new import_docx2.TableRow({
2448
+ children: row.map((cell, colI) => new import_docx2.TableCell({
2449
+ children: cell.type == "text" ? [new import_docx2.Paragraph({
2450
+ children: renderText(cell.text, node.sourceLine),
2451
+ alignment: node.align[colI] == "c" ? "center" : node.align[colI] == "r" ? "right" : "left",
2452
+ indent: { firstLine: 0 },
2453
+ spacing: { after: 0, line: 240 * 1.25 }
2454
+ })] : []
2455
+ }))
2456
+ }))
2457
+ });
2458
+ }, renderNode2 = function(node, prevChild, prevNode) {
895
2459
  switch (node.type) {
896
2460
  case "text":
897
- return new import_docx.Paragraph({
898
- children: renderText(node.text),
2461
+ return new import_docx2.Paragraph({
2462
+ children: renderText(node.text, node.sourceLine),
899
2463
  indent: node.noIndent ? { firstLine: 0 } : {},
900
2464
  ...node.center ? { alignment: "center", indent: { firstLine: 0 } } : {},
901
2465
  spacing: {
902
2466
  ...node.noMargin ? { after: 0 } : {},
903
- ...prevChild instanceof import_docx.Table ? { before: (doc.table.spacing.after ?? doc.text.spacing.after) * 20 } : {}
2467
+ ...prevChild instanceof import_docx2.Table ? { before: (doc.table.spacing.after ?? doc.text.spacing.after) * 20 } : {}
904
2468
  }
905
2469
  });
906
2470
  case "title":
@@ -908,20 +2472,20 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
908
2472
  const level = node.level == 0 ? 1 : node.level;
909
2473
  const styles = doc.headings[`h${level}`];
910
2474
  if (styles.uppercase) node.text.forEach((r) => r.text = r.text.toUpperCase());
911
- return new import_docx.Paragraph({
912
- children: renderText(node.text, styles.size),
2475
+ return new import_docx2.Paragraph({
2476
+ children: renderText(node.text, node.sourceLine, styles.size),
913
2477
  style: `${node.level}`,
914
2478
  ...node.center ? { alignment: "center", indent: { firstLine: 0 } } : {},
915
- ...!node.center && node.level != 0 && styles.indent_full ? { indent: { firstLine: 0, left: (0, import_docx.convertMillimetersToTwip)(12.5) } } : {},
2479
+ ...!node.center && node.level != 0 && styles.indent_full ? { indent: { firstLine: 0, left: (0, import_docx2.convertMillimetersToTwip)(12.5) } } : {},
916
2480
  spacing: {
917
2481
  before: styles.spacing.before * 20,
918
2482
  after: styles.spacing.after * 20
919
2483
  }
920
2484
  });
921
2485
  case "pageBreak":
922
- if (!(prevChild instanceof import_docx.Paragraph))
923
- return new import_docx.Paragraph({ children: [new import_docx.PageBreak()] });
924
- prevChild.addChildElement(new import_docx.PageBreak());
2486
+ if (!(prevChild instanceof import_docx2.Paragraph))
2487
+ return new import_docx2.Paragraph({ children: [new import_docx2.PageBreak()] });
2488
+ prevChild.addChildElement(new import_docx2.PageBreak());
925
2489
  return [];
926
2490
  case "list":
927
2491
  let renderList2 = function(node2, level2 = 0) {
@@ -932,8 +2496,8 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
932
2496
  for (const item of node2.items) {
933
2497
  if (item.type == "list") renderList2({ ...item, alternativeStyle: !!node2.alternativeStyle }, level2 + 1);
934
2498
  else {
935
- items.push(new import_docx.Paragraph({
936
- children: renderText(item.text),
2499
+ items.push(new import_docx2.Paragraph({
2500
+ children: renderText(item.text, item.sourceLine ?? node2.sourceLine),
937
2501
  style: STYLE_list,
938
2502
  numbering: { reference: id, level: level2 },
939
2503
  spacing: {
@@ -953,36 +2517,39 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
953
2517
  };
954
2518
  numbering.push(list);
955
2519
  const items = [];
956
- let addMargin = prevChild instanceof import_docx.Table;
2520
+ let addMargin = prevChild instanceof import_docx2.Table;
957
2521
  renderList2(node);
958
2522
  return items;
959
2523
  case "table":
960
- 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);
961
- 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);
2524
+ if (node.header !== false && node.rows[0] && doc.table.heading.style == "italic") node.rows[0].forEach((n) => n.type == "text" ? n.text.forEach((r) => r.italic = true) : 0);
2525
+ if (node.header !== false && node.rows[0] && doc.table.heading.style == "bold") node.rows[0].forEach((n) => n.type == "text" ? n.text.forEach((r) => r.bold = true) : 0);
962
2526
  const spacingInner = Math.max(doc.table.spacing.after ?? doc.text.spacing.after, doc.table.spacing.before ?? 0);
963
2527
  return [
964
2528
  ...node.title ? [
965
- new import_docx.Paragraph({
966
- children: renderText(node.title, doc.table.title.size),
2529
+ new import_docx2.Paragraph({
2530
+ children: renderText(node.title, node.sourceLine, doc.table.title.size),
967
2531
  style: STYLE_table_title,
968
- ...prevChild instanceof import_docx.Table ? { spacing: { before: spacingInner * 20 } } : doc.table.spacing.before ? { spacing: { before: doc.table.spacing.before * 20 } } : {}
2532
+ ...prevChild instanceof import_docx2.Table ? { spacing: { before: spacingInner * 20 } } : doc.table.spacing.before ? { spacing: { before: doc.table.spacing.before * 20 } } : {}
969
2533
  })
970
- ] : prevChild instanceof import_docx.Table ? [
971
- new import_docx.Paragraph({ spacing: { line: 20, before: spacingInner * 20, after: 0 } })
2534
+ ] : prevChild instanceof import_docx2.Table ? [
2535
+ new import_docx2.Paragraph({ spacing: { line: 20, before: spacingInner * 20, after: 0 } })
972
2536
  ] : doc.table.spacing.before ? [
973
- new import_docx.Paragraph({ spacing: { line: 20, before: doc.table.spacing.before * 20, after: 0 } })
2537
+ new import_docx2.Paragraph({ spacing: { line: 20, before: doc.table.spacing.before * 20, after: 0 } })
974
2538
  ] : [],
975
- new import_docx.Table({
2539
+ new import_docx2.Table({
976
2540
  // width: { type: "pct", size: 100 },
977
- width: { type: "dxa", size: 9572 },
978
- rows: node.rows.map((row, rowI) => new import_docx.TableRow({
979
- tableHeader: rowI == 0,
2541
+ width: {
2542
+ type: "dxa",
2543
+ size: (0, import_docx2.convertMillimetersToTwip)(section.orientation === "landscape" ? 255.8 : 168.8)
2544
+ },
2545
+ rows: node.rows.map((row, rowI) => new import_docx2.TableRow({
2546
+ tableHeader: node.header !== false && rowI == 0,
980
2547
  cantSplit: true,
981
- children: row.map((item, colI) => new import_docx.TableCell({
2548
+ children: row.map((item, colI) => new import_docx2.TableCell({
982
2549
  children: item.type != "text" ? renderNodeL2(item) : [
983
- new import_docx.Paragraph({
984
- children: renderText(item.text, node.normalFontSize ? void 0 : doc.table.text.size),
985
- alignment: rowI == 0 ? doc.table.heading.align : node.align[colI] == "c" ? "center" : node.align[colI] == "r" ? "right" : "left",
2550
+ new import_docx2.Paragraph({
2551
+ children: renderText(item.text, node.sourceLine, node.normalFontSize ? void 0 : doc.table.text.size),
2552
+ alignment: node.header !== false && rowI == 0 ? doc.table.heading.align : node.align[colI] == "c" ? "center" : node.align[colI] == "r" ? "right" : "left",
986
2553
  indent: { firstLine: 0 },
987
2554
  spacing: { after: 0, line: 240 * doc.table.text.line_spacing }
988
2555
  })
@@ -993,20 +2560,20 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
993
2560
  ];
994
2561
  case "tableOfContents":
995
2562
  return [
996
- new import_docx.TableOfContents("\u041E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435", {
2563
+ new import_docx2.TableOfContents("\u041E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435", {
997
2564
  hyperlink: true,
998
2565
  headingStyleRange: "1-3"
999
2566
  }),
1000
- new import_docx.Paragraph({ children: [new import_docx.PageBreak()] })
2567
+ new import_docx2.Paragraph({ children: [new import_docx2.PageBreak()] })
1001
2568
  ];
1002
2569
  case "image":
1003
- const type = node.src.split(".").at(-1) || "";
2570
+ const type = (node.src.split(".").at(-1) || "").toLowerCase();
1004
2571
  if (!["jpg", "png", "gif", "bmp", "svg"].includes(type))
1005
2572
  throw new UserInputError(`Unsupported image format: "${type}", file: ${node.src}`);
1006
2573
  const img_path = getPath(node.src);
1007
- if (!fs3.existsSync(img_path))
2574
+ if (!fs4.existsSync(img_path))
1008
2575
  throw new UserInputError(`File not exist: ${node.src}`);
1009
- const data = fs3.readFileSync(img_path);
2576
+ const data = fs4.readFileSync(img_path);
1010
2577
  const dimensions = (0, import_image_size.imageSize)(data);
1011
2578
  const [MaxW, MaxH] = section.orientation == "landscape" ? [950, 600] : [600, 900];
1012
2579
  let [width, height] = [dimensions.width, dimensions.height];
@@ -1016,19 +2583,19 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1016
2583
  if (height > MaxH) [width, height] = [width / height * MaxH, MaxH];
1017
2584
  if (width > MaxW) [width, height] = [MaxW, height / width * MaxW];
1018
2585
  return [
1019
- new import_docx.Paragraph({
2586
+ new import_docx2.Paragraph({
1020
2587
  alignment: "center",
1021
2588
  indent: { firstLine: 0 },
1022
2589
  spacing: {
1023
2590
  line: 240,
1024
- lineRule: import_docx.LineRuleType.AT_LEAST,
2591
+ lineRule: import_docx2.LineRuleType.AT_LEAST,
1025
2592
  // For LibreOffice to not shrink image
1026
2593
  ...!node.text && doc.img.spacing.after !== void 0 ? { after: doc.img.spacing.after * 20 } : {},
1027
2594
  ...doc.img.spacing.before !== void 0 ? { before: doc.img.spacing.before * 20 } : {}
1028
2595
  },
1029
2596
  keepNext: !!node.text,
1030
2597
  children: [
1031
- new import_docx.ImageRun({
2598
+ new import_docx2.ImageRun({
1032
2599
  type,
1033
2600
  data,
1034
2601
  transformation: { width, height },
@@ -1037,8 +2604,8 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1037
2604
  ]
1038
2605
  }),
1039
2606
  ...node.text ? [
1040
- new import_docx.Paragraph({
1041
- children: renderText(node.text, doc.img.text.size),
2607
+ new import_docx2.Paragraph({
2608
+ children: renderText(node.text, node.sourceLine, doc.img.text.size),
1042
2609
  alignment: "center",
1043
2610
  indent: { firstLine: 0 },
1044
2611
  spacing: {
@@ -1052,31 +2619,97 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1052
2619
  const code = doc.code.highlight && renderCodeHighlighting(node.code, node.lang);
1053
2620
  return [
1054
2621
  ...node.title ? [
1055
- new import_docx.Paragraph({
1056
- children: renderText(node.title, doc.code.title.size),
2622
+ new import_docx2.Paragraph({
2623
+ children: renderText(node.title, node.sourceLine, doc.code.title.size),
1057
2624
  style: STYLE_code_title
1058
2625
  })
1059
2626
  ] : prevNode?.type == "code" ? [
1060
- new import_docx.Paragraph({ spacing: { line: 20 } })
2627
+ new import_docx2.Paragraph({ spacing: { line: 20 } })
1061
2628
  ] : [],
1062
- ...code ? code : node.code.split("\n").map((p, i) => new import_docx.Paragraph({
1063
- children: [new import_docx.TextRun(p)],
2629
+ ...code ? code : node.code.split("\n").map((p, i) => new import_docx2.Paragraph({
2630
+ children: [new import_docx2.TextRun(p)],
1064
2631
  style: STYLE_code,
1065
2632
  ...i == 0 && !node.title && doc.code.spacing.before && prevNode?.type != "code" ? { spacing: { before: doc.code.spacing.before * 20 } } : {}
1066
2633
  }))
1067
2634
  ];
2635
+ case "math":
2636
+ const formulaWidth = (0, import_docx2.convertMillimetersToTwip)(section.orientation == "landscape" ? 255.8 : 168.8);
2637
+ const number = node.title?.map((rune) => rune.text).join("") || "";
2638
+ const sideWidth = Math.max(
2639
+ (0, import_docx2.convertMillimetersToTwip)(5),
2640
+ Math.ceil(estimateNumberWidthPt(number, doc.text.size) * 20 + (0, import_docx2.convertMillimetersToTwip)(3))
2641
+ );
2642
+ return [
2643
+ ...prevNode?.type != "math" ? [
2644
+ new import_docx2.Paragraph({ indent: { firstLine: 0 }, spacing: { line: 20, after: doc.formula.spacing.before * 20 } })
2645
+ ] : [],
2646
+ new import_docx2.Table({
2647
+ width: { type: "dxa", size: formulaWidth },
2648
+ borders: { top: { style: import_docx2.BorderStyle.NONE }, bottom: { style: import_docx2.BorderStyle.NONE }, left: { style: import_docx2.BorderStyle.NONE }, right: { style: import_docx2.BorderStyle.NONE }, insideHorizontal: { style: import_docx2.BorderStyle.NONE }, insideVertical: { style: import_docx2.BorderStyle.NONE } },
2649
+ rows: [new import_docx2.TableRow({
2650
+ children: [
2651
+ new import_docx2.TableCell({ width: { type: "dxa", size: sideWidth }, children: [new import_docx2.Paragraph({ indent: { firstLine: 0 }, spacing: { after: 0 } })] }),
2652
+ new import_docx2.TableCell({
2653
+ children: [
2654
+ new import_docx2.Paragraph({ alignment: import_docx2.AlignmentType.CENTER, indent: { firstLine: 0 }, spacing: { after: 0 }, children: [renderMath(node.latex, true, node.sourceLine)] })
2655
+ ]
2656
+ }),
2657
+ new import_docx2.TableCell({ width: { type: "dxa", size: sideWidth }, children: [new import_docx2.Paragraph({
2658
+ indent: { firstLine: 0 },
2659
+ spacing: { line: 240, after: 0 },
2660
+ alignment: import_docx2.AlignmentType.RIGHT,
2661
+ children: renderText(node.title || [], node.sourceLine)
2662
+ })], verticalAlign: import_docx2.VerticalAlignTable.CENTER })
2663
+ ]
2664
+ })]
2665
+ }),
2666
+ new import_docx2.Paragraph({ indent: { firstLine: 0 }, spacing: { line: 20, after: doc.formula.spacing.after * 20 } })
2667
+ ];
1068
2668
  case "externalDoc":
1069
2669
  const doc_path = getPath(node.path);
1070
- if (!fs3.existsSync(doc_path))
2670
+ if (!fs4.existsSync(doc_path))
1071
2671
  throw new UserInputError(`File not exist: ${node.path}`);
1072
- const ext = import_path2.default.extname(doc_path);
2672
+ const ext = import_path3.default.extname(doc_path);
1073
2673
  if (ext != ".docx" && ext != ".pdf")
1074
2674
  throw new UserInputError(`File not .docx or .pdf: ${node.path}`);
1075
- return new import_docx.Paragraph({
2675
+ return new import_docx2.Paragraph({
1076
2676
  text: `!!(${doc_path})${JSON.stringify(node.dict)}`,
1077
2677
  indent: { firstLine: 0 },
1078
2678
  alignment: "left"
1079
2679
  });
2680
+ case "admonition":
2681
+ const style = `xAdmonition${node.admonitionType == "note" ? "" : node.admonitionType}`;
2682
+ const admonition = doc.admonition[node.admonitionType];
2683
+ const color = "#" + admonition.color;
2684
+ const icon = admonition.icon ? [new import_docx2.ImageRun({
2685
+ type: "svg",
2686
+ data: Buffer.from(admonitionIcons[node.admonitionType](admonition.title_color ? color : "#000000")),
2687
+ transformation: { width: admonition.icon_size, height: admonition.icon_size },
2688
+ fallback: {
2689
+ data: Buffer.from((admonition.title_color ? admonitionIconsFallback : admonitionIconsFallbackBlack)[node.admonitionType], "base64"),
2690
+ type: "png"
2691
+ }
2692
+ }), new import_docx2.TextRun(" ")] : [];
2693
+ const prevIsSameType = prevNode?.type == "admonition" && prevNode.admonitionType == node.admonitionType;
2694
+ const showTitle = node.title.map((r) => r.text).join("") != "";
2695
+ return [
2696
+ ...prevIsSameType ? [
2697
+ new import_docx2.Paragraph({ spacing: { line: 20, before: 0, after: 0 } })
2698
+ ] : [],
2699
+ ...showTitle ? [
2700
+ new import_docx2.Paragraph({
2701
+ style,
2702
+ children: [...icon, ...renderText(admonition.title_color ? node.title.map((r) => ({ ...r, color })) : node.title, node.sourceLine)],
2703
+ keepNext: true,
2704
+ ...prevIsSameType ? { spacing: { before: 0 } } : {}
2705
+ })
2706
+ ] : [],
2707
+ new import_docx2.Paragraph({
2708
+ style,
2709
+ children: renderText(node.text, node.sourceLine),
2710
+ ...prevIsSameType && !showTitle ? { spacing: { before: 0 } } : {}
2711
+ })
2712
+ ];
1080
2713
  case "sectionBreak":
1081
2714
  return [];
1082
2715
  default:
@@ -1084,12 +2717,20 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1084
2717
  throw new Error("switch default");
1085
2718
  }
1086
2719
  }, renderNodeL2 = function(node, prevChild, prevNode) {
1087
- const r = renderNode2(node, prevChild, prevNode);
1088
- if (r instanceof Array) return r;
1089
- return [r];
2720
+ try {
2721
+ const r = renderNode2(node, prevChild, prevNode);
2722
+ if (r instanceof Array) return r;
2723
+ return [r];
2724
+ } catch (error) {
2725
+ const message = error instanceof Error ? error.message : String(error);
2726
+ if (/^Line -?\d+:/.test(message)) throw error;
2727
+ throw new Error(`${node.sourceLine ? `Line ${node.sourceLine}: ` : ""}${message}`, { cause: error });
2728
+ }
1090
2729
  };
1091
- var renderNode = renderNode2, renderNodeL = renderNodeL2;
2730
+ var renderHeaderFooter = renderHeaderFooter2, renderHeaderFooterTable = renderHeaderFooterTable2, renderNode = renderNode2, renderNodeL = renderNodeL2;
1092
2731
  const children = [];
2732
+ const header = renderHeaderFooter2(section.header, false);
2733
+ const footer = renderHeaderFooter2(section.footer, true);
1093
2734
  sections.push({
1094
2735
  children,
1095
2736
  properties: {
@@ -1104,38 +2745,26 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1104
2745
  // height: convertMillimetersToTwip(297),
1105
2746
  // },
1106
2747
  size: {
1107
- orientation: section.orientation == "landscape" ? import_docx.PageOrientation.LANDSCAPE : import_docx.PageOrientation.PORTRAIT
2748
+ orientation: section.orientation == "landscape" ? import_docx2.PageOrientation.LANDSCAPE : import_docx2.PageOrientation.PORTRAIT
1108
2749
  },
1109
2750
  pageNumbers: !section.pageStart ? {} : {
1110
2751
  start: section.pageStart
1111
2752
  },
1112
2753
  margin: {
1113
- top: (0, import_docx.convertMillimetersToTwip)(20),
1114
- left: (0, import_docx.convertMillimetersToTwip)(30),
1115
- right: (0, import_docx.convertMillimetersToTwip)(15),
1116
- bottom: (0, import_docx.convertMillimetersToTwip)(20)
2754
+ top: (0, import_docx2.convertMillimetersToTwip)(20),
2755
+ left: (0, import_docx2.convertMillimetersToTwip)(30),
2756
+ right: (0, import_docx2.convertMillimetersToTwip)(15),
2757
+ bottom: (0, import_docx2.convertMillimetersToTwip)(20)
1117
2758
  }
1118
2759
  }
1119
2760
  },
1120
- footers: {
1121
- default: new import_docx.Footer({
1122
- children: [
1123
- new import_docx.Paragraph({
1124
- alignment: import_docx.AlignmentType.CENTER,
1125
- children: [new import_docx.TextRun({
1126
- children: section.displayPageNum ? [import_docx.PageNumber.CURRENT] : []
1127
- })],
1128
- indent: { firstLine: 0 },
1129
- spacing: { line: 240 }
1130
- })
1131
- ]
1132
- })
1133
- }
2761
+ ...header ? { headers: { default: header } } : {},
2762
+ ...footer ? { footers: { default: footer } } : {}
1134
2763
  });
1135
2764
  for (let i = 0; i < section.nodes.length; i++)
1136
2765
  children.push(...renderNodeL2(section.nodes[i], children.at(-1), section.nodes[i - 1]));
1137
2766
  }
1138
- const docx = new import_docx.Document({
2767
+ const docx = new import_docx2.Document({
1139
2768
  sections,
1140
2769
  externalStyles: genXml_style(assets, doc),
1141
2770
  // features: { updateFields: true },
@@ -1153,7 +2782,7 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1153
2782
  // creator: doc.author,
1154
2783
  // lastModifiedBy: doc.author,
1155
2784
  });
1156
- const buffer = await import_docx.Packer.toBuffer(docx, void 0, [
2785
+ const buffer = await import_docx2.Packer.toBuffer(docx, void 0, [
1157
2786
  { path: "docProps/app.xml", data: genXml_app({ totalTime: doc.etime }) },
1158
2787
  {
1159
2788
  path: "docProps/core.xml",
@@ -1165,21 +2794,25 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1165
2794
  })
1166
2795
  }
1167
2796
  ]);
1168
- fs3.writeFileSync(fout, buffer);
1169
- function renderText(text, size) {
2797
+ fs4.writeFileSync(fout, buffer);
2798
+ function renderText(text, sourceLine, size) {
1170
2799
  function renderRune(rune, link = false) {
1171
- if (rune.anchor) return new import_docx.Bookmark({
2800
+ if (rune.anchor) return new import_docx2.Bookmark({
1172
2801
  id: rune.anchor,
1173
2802
  children: [renderRune({ ...rune, anchor: void 0 })]
1174
2803
  });
1175
2804
  if (rune.link) {
1176
2805
  const children2 = [renderRune({ ...rune, link: void 0 }, true)];
1177
- return rune.link.startsWith("#") ? new import_docx.InternalHyperlink({ children: children2, anchor: rune.link.slice(1) }) : new import_docx.ExternalHyperlink({ children: children2, link: rune.link });
2806
+ return rune.link.startsWith("#") ? new import_docx2.InternalHyperlink({ children: children2, anchor: rune.link.slice(1) }) : new import_docx2.ExternalHyperlink({ children: children2, link: rune.link });
1178
2807
  }
2808
+ if (rune.type == "math") return renderMath(rune.text, false, sourceLine);
1179
2809
  let children = null;
1180
- if (rune.type == "val" && rune.text == "pages") {
2810
+ if (rune.type == "val" && rune.text == "page") {
1181
2811
  rune.type = "text";
1182
- children = doc.totalPagesOffset == 0 ? [import_docx.PageNumber.TOTAL_PAGES] : [
2812
+ children = [import_docx2.PageNumber.CURRENT];
2813
+ } else if (rune.type == "val" && rune.text == "pages") {
2814
+ rune.type = "text";
2815
+ children = doc.totalPagesOffset == 0 ? [import_docx2.PageNumber.TOTAL_PAGES] : [
1183
2816
  // Complex Formula Field: { = { NUMPAGES } + 1 }
1184
2817
  // Outer field start: "="
1185
2818
  new RawXml("w:fldChar", { "w:fldCharType": "begin" }),
@@ -1200,7 +2833,7 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1200
2833
  new RawXml("w:fldChar", { "w:fldCharType": "end" })
1201
2834
  ];
1202
2835
  }
1203
- return new import_docx.TextRun({
2836
+ return new import_docx2.TextRun({
1204
2837
  ...children ? { children } : { text: rune.text },
1205
2838
  language: { value: rune.lang == "en" ? "en-US" : "ru-RU" },
1206
2839
  ...rune.linebreak ? { break: 1 } : {},
@@ -1261,12 +2894,41 @@ async function serializeDocx(doc, fout, workdir, assets, checkFilesIsInsidePath)
1261
2894
  }
1262
2895
  }
1263
2896
  }
2897
+ function renderMath(latex, para, sourceLine) {
2898
+ try {
2899
+ return latexToOmml(latex, para);
2900
+ } catch (error) {
2901
+ logwarn(`${sourceLine ? `Line ${doc.mapSourceLine(sourceLine + 1)}: ` : ""}Formula was not converted: ${error instanceof Error ? error.message : String(error)}`);
2902
+ return new import_docx2.TextRun(latex);
2903
+ }
2904
+ }
1264
2905
  }
2906
+ var admonitionIcons = {
2907
+ note: (c) => `<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><style>.a{fill:${c}}</style><path class="a" d="m13 12q0-0.4-0.3-0.7-0.3-0.3-0.7-0.3-0.4 0-0.7 0.3-0.3 0.3-0.3 0.7v4q0 0.4 0.3 0.7 0.3 0.3 0.7 0.3 0.4 0 0.7-0.3 0.3-0.3 0.3-0.7zm-1-2.5c0.3 0 0.6-0.1 0.9-0.4 0.2-0.2 0.3-0.5 0.3-0.8q0-0.6-0.3-0.9c-0.3-0.3-0.6-0.4-0.9-0.4-0.3 0-0.6 0.1-0.9 0.4q-0.3 0.3-0.3 0.9c0 0.3 0.1 0.6 0.3 0.8 0.3 0.3 0.6 0.4 0.9 0.4z"/><path fill-rule="evenodd" class="a" d="m22 12c0 5.5-4.5 10-10 10-5.5 0-10-4.5-10-10 0-5.5 4.5-10 10-10 5.5 0 10 4.5 10 10zm-15.7 5.7c1.5 1.5 3.6 2.3 5.7 2.3 2.1 0 4.2-0.8 5.7-2.3 1.5-1.5 2.3-3.6 2.3-5.7 0-2.1-0.8-4.2-2.3-5.7-1.5-1.5-3.6-2.3-5.7-2.3-2.1 0-4.2 0.8-5.7 2.3-1.5 1.5-2.3 3.6-2.3 5.7 0 2.1 0.8 4.2 2.3 5.7z"/></svg>`,
2908
+ info: (c) => `<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><style>.a{fill:${c}}</style><path class="a" d="m13 12q0-0.4-0.3-0.7-0.3-0.3-0.7-0.3-0.4 0-0.7 0.3-0.3 0.3-0.3 0.7v4q0 0.4 0.3 0.7 0.3 0.3 0.7 0.3 0.4 0 0.7-0.3 0.3-0.3 0.3-0.7zm-1-2.5c0.3 0 0.6-0.1 0.9-0.4 0.2-0.2 0.3-0.5 0.3-0.8q0-0.6-0.3-0.9c-0.3-0.3-0.6-0.4-0.9-0.4-0.3 0-0.6 0.1-0.9 0.4-0.2 0.2-0.3 0.5-0.3 0.9 0 0.3 0.1 0.6 0.3 0.8 0.3 0.3 0.6 0.4 0.9 0.4z"/><path fill-rule="evenodd" class="a" d="m22 12c0 5.5-4.5 10-10 10-5.5 0-10-4.5-10-10 0-5.5 4.5-10 10-10 5.5 0 10 4.5 10 10zm-15.7 5.7c1.5 1.5 3.6 2.3 5.7 2.3 2.1 0 4.2-0.8 5.7-2.3 1.5-1.5 2.3-3.6 2.3-5.7 0-2.1-0.8-4.2-2.3-5.7-1.5-1.5-3.6-2.3-5.7-2.3-2.1 0-4.2 0.8-5.7 2.3-1.5 1.5-2.3 3.6-2.3 5.7 0 2.1 0.8 4.2 2.3 5.7z"/></svg>`,
2909
+ tip: (c) => `<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><style>.a{fill:${c}}</style><path class="a" d="m8.1 20c0.2 0.9 0.7 1.6 1.5 2.2 0.7 0.5 1.5 0.8 2.4 0.8 0.9 0 1.7-0.3 2.4-0.8 0.8-0.6 1.3-1.3 1.5-2.2q0.2 0 0.4-0.1 0.1-0.1 0.3-0.2 0.1-0.1 0.2-0.3 0.1-0.2 0.1-0.4v-2.5q0.8-0.6 1.5-1.3 0.7-0.8 1.1-1.7 0.5-0.9 0.8-1.9 0.2-1 0.2-2.1c0-4.7-3.8-8.5-8.5-8.5-4.7 0-8.5 3.8-8.5 8.5q0 1.1 0.2 2.1 0.3 1 0.8 1.9 0.4 0.9 1.1 1.7 0.7 0.7 1.5 1.3v2.5q0 0.2 0.1 0.4 0.1 0.2 0.2 0.3 0.2 0.1 0.3 0.2 0.2 0.1 0.4 0.1zm6.8-3v1h-5.8v-1zm-1.1 3q-0.3 0.5-0.7 0.7-0.5 0.3-1 0.3-0.6 0-1-0.3-0.5-0.2-0.8-0.7zm-1.7-17c3.6 0 6.5 2.9 6.5 6.5q0 0.8-0.2 1.6-0.2 0.8-0.6 1.5-0.4 0.8-0.9 1.4-0.5 0.6-1.2 1h-7.2q-0.6-0.4-1.2-1-0.5-0.6-0.9-1.4-0.4-0.7-0.6-1.5-0.2-0.8-0.2-1.6c0-3.6 2.9-6.5 6.5-6.5z"/></svg>`,
2910
+ warning: (c) => `<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><style>.a{fill:${c}}</style><path class="a" d="m9.4 4.3c1.2-1.9 4-1.9 5.2 0l7.4 12.1c1.2 2-0.2 4.6-2.6 4.6h-14.8c-2.4 0-3.8-2.6-2.6-4.6zm3.4 1.1c-0.4-0.7-1.3-0.7-1.7 0l-7.4 12.1c-0.4 0.7 0.1 1.6 0.8 1.6h14.9c0.8 0 1.3-0.9 0.9-1.6zm-0.9 3.7c0.6 0 1 0.5 1 1v3c0 0.6-0.4 1-1 1-0.6 0-1-0.4-1-1v-3c0-0.5 0.4-1 1-1zm-1.1 7.5c0-0.6 0.5-1.1 1.1-1.1 0.6 0 1.2 0.5 1.2 1.1 0 0.7-0.6 1.2-1.2 1.2-0.6 0-1.1-0.5-1.1-1.2z"/></svg>`,
2911
+ danger: (c) => `<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><style>.a{fill:${c}}.b{fill:none;stroke:${c};stroke-linecap:round;stroke-linejoin:round;stroke-width:2}</style><path class="a" d="m12 14.5c-0.3 0-0.6 0.1-0.9 0.4-0.2 0.2-0.3 0.5-0.3 0.8q0 0.6 0.3 0.9c0.3 0.3 0.6 0.4 0.9 0.4 0.3 0 0.6-0.1 0.9-0.4q0.3-0.3 0.3-0.9c0-0.3-0.1-0.6-0.3-0.8-0.3-0.3-0.6-0.4-0.9-0.4z"/><path fill-rule="evenodd" class="b" d="m12 8v4"/><path class="b" d="m15.3 2q0.2 0 0.4 0 0.2 0.1 0.4 0.2 0.2 0 0.3 0.1 0.2 0.1 0.3 0.3l4.7 4.7q0.2 0.1 0.3 0.3 0.1 0.1 0.1 0.3 0.1 0.2 0.2 0.4 0 0.2 0 0.4v6.6q0 0.2 0 0.4-0.1 0.2-0.2 0.4 0 0.2-0.1 0.3-0.1 0.2-0.3 0.3l-4.7 4.7q-0.1 0.2-0.3 0.3-0.1 0.1-0.3 0.1-0.2 0.1-0.4 0.2-0.2 0-0.4 0h-6.6q-0.2 0-0.4 0-0.2-0.1-0.4-0.2-0.2 0-0.3-0.1-0.2-0.1-0.3-0.3l-4.7-4.7q-0.2-0.1-0.3-0.3-0.1-0.1-0.1-0.3-0.1-0.2-0.2-0.4 0-0.2 0-0.4v-6.6q0-0.2 0-0.4 0.1-0.2 0.2-0.4 0-0.2 0.1-0.3 0.1-0.2 0.3-0.3l4.7-4.7q0.1-0.2 0.3-0.3 0.1-0.1 0.3-0.1 0.2-0.1 0.4-0.2 0.2 0 0.4 0z"/></svg>`
2912
+ };
2913
+ var admonitionIconsFallback = {
2914
+ note: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAilBMVEUAAABmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmbNZZ8EAAAALnRSTlMA//BXB/7YePSoRaAMKt3USM91y08CZiK8tUzjLxM82zjGblsPPSRhBkJzadIoQt+BPAAAAMBJREFUeJydUVcOwjAUi9Mm3YsOoLRlb7j/9RDJK22EEAL/OLKd5A3G/oVtBbnLs8CyTd2PQYj9se4IzKuubffVDMIZ6eBpfy44Xk4q3GhIRa6gVLiApThJ1M9bSF2BhUTxAZg+uZQ6yDxc9dVupfkCT7HUwQENpGIOauqWad6BkxFqAaBqyJCITKOhpzxsTGNCn/fl9ka5pHJtapDla0XHvkFWC343RnL+NkQ99vrEmF2YY/+8KLXajLv522p/wANc8QfHdtgFgwAAAABJRU5ErkJggg==`,
2915
+ info: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAilBMVEUAAAAZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtIZdtL9UeA9AAAALnRSTlMA//BXB/7YePSoRaAMKt3USM91y08CZiK8tUzjLxM82zjGblsPPSRhBkJzadIoQt+BPAAAAMBJREFUeJydUVcOwjAUi9Mm3YsOoLRlb7j/9RDJK22EEAL/OLKd5A3G/oVtBbnLs8CyTd2PQYj9se4IzKuubffVDMIZ6eBpfy44Xk4q3GhIRa6gVLiApThJ1M9bSF2BhUTxAZg+uZQ6yDxc9dVupfkCT7HUwQENpGIOauqWad6BkxFqAaBqyJCITKOhpzxsTGNCn/fl9ka5pHJtapDla0XHvkFWC343RnL+NkQ99vrEmF2YY/+8KLXajLv522p/wANc8QfHdtgFgwAAAABJRU5ErkJggg==`,
2916
+ tip: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAllBMVEUAAAAufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTIufTLBWjFSAAAAMnRSTlMA//AF9MXq5ssCgtub1XmmJgghfRkRC+exGm0tRBX+i2c1Tt8pMHC0RwxdtsOoo64eS7UJBqAAAADPSURBVHichVLZEoIwENtU7luUUwUB79v//zkHpKWiM+Ypk+x2szsl+ofAUhlTrWAkR7cCHQonlvWwASvrR7Sc6XBXgx67sOc9vcCYCGMmdKKjijXnE4Z6aF+g4fQJ3ZQGGtj2bIernKTESYxwZCOHJzpS2bCQ9+wANiQkUrHkqbQhIVEFTUTxoEWcm4YYQTS1YWQ99eFK71bK+4QtFL5Fh1A4SijrRAm6a2XQP3VKeMfYOHPjY9cWKfarqYP7WKcFa+vZ5sugja8l/vgv/MALHToJTMdMgakAAAAASUVORK5CYII=`,
2917
+ warning: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAllBMVEUAAACyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagCyagD2Sl3HAAAAMnRSTlMA/w3r5vwbWbsElS1drcsiElT5ArX2wo045GaR779hCUx02KB7BdPiPyiCaxZSMsa5W/G4KzAAAADCSURBVHictZDJEoJADES7GZBFdlABFdz39f9/zmIoCge9WeaS5HVNkmngD6F5pKd9EeYkaX3yJ+NDRJofgwQ3gEO9P2zKlQ1oOicqHxrM6hzROCrCnWvYuQekHL/zkrMQA+rAYES346FggUbAkqLb79BHK9g7Tlt+ozEEUIlH3WVk3QFIfPXG5j2AgvtKFudr81edpcwzLiQIGG9lETX73da55NQeOpeWmUx79tiWFC6i9luNPJSzx7GKYyvom/9TvACzaQfmlOkXxAAAAABJRU5ErkJggg==`,
2918
+ danger: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAdVBMVEUAAADTLy+/ICDSLi7SLi7GHBzPKSnSLy/SLi7MGhrTLy/TLy/SLy/RLi7SLy/SLi7TLi7KLCzRLi7SLi7KKyvTLi7TLy/EJyfTLi6/KyvTLy/TLy/SLi7TLy/MKSnMKyvTLy/SLy/TLi7OJyfSLi7TLy/TLy/z9/9QAAAAJ3RSTlMA/wi9wgklCyEK7L/UFuXA4B0c6Rj+Vg2zDMXc2LkZHre0lhqmySRpaHOvAAAAtElEQVR4nKVRRxLDIBBbGdx77yX1/0/M2EBMHE8u0QWtBCwriH6juECiKXQ9DJQOBOGuzz1YK2jLMNyU7kRghioMhmQW1Mo1ncjgiKyVTB5iTSdyObz1BdeSu0LxfbHaXXknIqCWWwFJ6o29yyPDH4Yvm38ZO/BpVNXBkOM9AUcwczNGyAHtcbEF4WiIKPUQm8dI0vMQ8y3Ek9hlK6I0wSJvMxn6bD8+DedfS5Q9lN5p+0/xArzsBn7bxA9sAAAAAElFTkSuQmCC`
2919
+ };
2920
+ var admonitionIconsFallbackBlack = {
2921
+ note: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAilBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAggvAAAALnRSTlMA//AHeFjY9N2gDCpEqM3TSToi47XVR9D9Zky8L3RWPRNPxm4CUFsPJGFpKAbKjdKbTAAAAMRJREFUeJydUdkSgjAM7BbKfYjKKQp4n///e860AdpxfNC8bGY3bZINY/+GJfzE5aUvLJOPPFB4kc7bwLru+r6rN4Ct83wx5ic+K0XlhnNV6FZUFaywk5insvMZjppAIJd4BZYycSAkxrirp1mmcIuYClThFC0ciRy0VJoovICTECgCoGlIcBCaQktfxTiYwthcIDWEo0fjWrQge+0l3MYFWQP+0C3BZLBu4qCZqGxvnoxZg2k7Y8WXQ8nTltxNPk77Q7wBVQsHvaZMK8YAAAAASUVORK5CYII=`,
2922
+ info: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAilBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAggvAAAALnRSTlMA//AHeFjY9N2gDCpEqM3TSToi47XVR9D9Zky8L3RWPRNPxm4CUFsPJGFpKAbKjdKbTAAAAMRJREFUeJydUdkSgjAM7BbKfYjKKQp4n///e860AdpxfNC8bGY3bZINY/+GJfzE5aUvLJOPPFB4kc7bwLru+r6rN4Ct83wx5ic+K0XlhnNV6FZUFaywk5insvMZjppAIJd4BZYycSAkxrirp1mmcIuYClThFC0ciRy0VJoovICTECgCoGlIcBCaQktfxTiYwthcIDWEo0fjWrQge+0l3MYFWQP+0C3BZLBu4qCZqGxvnoxZg2k7Y8WXQ8nTltxNPk77Q7wBVQsHvaZMK8YAAAAASUVORK5CYII=`,
2923
+ tip: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAh1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3YishAAAALXRSTlMA/+gFxBrmCvAH9EXbmyd9sC+kedXxTckiEW3ryx8VZ4s1gt8rqHC1XQyDshgZvchdAAAAyUlEQVR4nIWS5w7CMAyEfR20dO/SSSdlvf/zIaokDQWJ+3XyZ8dDIfonb9BMUxu8XbiIwOQacrwZkXZZU9j+AUm7xY0EzpNZDbkqgA9H5/6W48y9aiLbyieM3GY4yA1rhMxdMMugw1W0cGVQIhYVgQzuKJmzYW4TEmmw+VTVNiFRD0WkxVAKAXLRgujooGYbHmck0ru9xW8IWHyLVSdBrJMcJ1KwvqV/HmEFTHuwcPDYAQqwtIb7eYNVYfrOT6cvQF5UKdH+L/zQCzA0CJnLbfrbAAAAAElFTkSuQmCC`,
2924
+ warning: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAllBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6C80qAAAAMnRSTlMA/w3mA/xUu1kb610AyyKtEi35lbXvwvZhv2aPCTnYixagayh7TDKSBeLTdII/xrk2W23LF/kAAADFSURBVHictZDJcsIwEET7WbINosDGLGELS8Kanf//OUpyucAmN4q+jOZ1aUZq6QmKMsiif4wpQHrPzxTfCbTuBjm20gDTHDZnaaXIMK/zfsyrrwnxe834YSNrMmnI+JZPGOVqY6T2C50rzx0zlYY+cdf9A7qqDPvBoeJ74r6khfv13R/4zqvL6nZheV/SjNMiHN6S8q+GSagjdgH0KI7hkJT7O1Vy9qt66DRE1mLYiMemwVg7n3ddJg+zx0UdF2mvGf5DugCExweZt6hkrgAAAABJRU5ErkJggg==`,
2925
+ danger: `iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAYFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6T+iNAAAAIHRSTlMA/wi9Cr8lwgwY7Bwhw7cW29Tl4OkdVh6z/bmWpsXXyQwvE4cAAACqSURBVHicpVFHEsIwEJPiFKeRXgjt/79ksNfEBA8XdNJKnpFXC/xGvlKw5r7edE4nu2bXl5ZKW6oV29LpVU8VuSFSHBZL09HTgahmn5rcgomnA3HG4vWDC7PYKkkizu18BUBKLkgh2rD3eGT8w0gk/MvYwU9jng+GrJeSlSxvjM0tqLeTJXHGFcAUqmQKlziaEgO1SxQwDTyJE/mHAvJ7+LRA+XB67b0P4gn4WAUqr4Oj0wAAAABJRU5ErkJggg==`
2926
+ };
1265
2927
  function addListItemLevel(levels, level, startIndex, itemCount, ordered, alternativeStyle, mark) {
1266
2928
  if (levels.find((v) => v.level == level)) return;
1267
2929
  levels.sort((a, b) => a.level - b.level);
1268
2930
  let indent = level;
1269
- const format = ordered ? import_docx.LevelFormat.DECIMAL : import_docx.LevelFormat.BULLET;
2931
+ const format = ordered ? import_docx2.LevelFormat.DECIMAL : import_docx2.LevelFormat.BULLET;
1270
2932
  for (let i = 1; i < levels.length + 1; i++) {
1271
2933
  const prevprevformat = levels[i - 2]?.format;
1272
2934
  const prevformat = levels[i - 1]?.format;
@@ -1292,15 +2954,15 @@ function addListItemLevel(levels, level, startIndex, itemCount, ordered, alterna
1292
2954
  } : {},
1293
2955
  paragraph: {
1294
2956
  indent: {
1295
- left: (0, import_docx.convertMillimetersToTwip)(left + 5 * indent),
1296
- hanging: (0, import_docx.convertMillimetersToTwip)(longList && !alternativeStyle ? 8 : 5),
1297
- ...alternativeStyle ? { firstLine: (0, import_docx.convertMillimetersToTwip)(12.5) } : {}
2957
+ left: (0, import_docx2.convertMillimetersToTwip)(left + 5 * indent),
2958
+ hanging: (0, import_docx2.convertMillimetersToTwip)(longList && !alternativeStyle ? 8 : 5),
2959
+ ...alternativeStyle ? { firstLine: (0, import_docx2.convertMillimetersToTwip)(12.5) } : {}
1298
2960
  }
1299
2961
  }
1300
2962
  }
1301
2963
  });
1302
2964
  }
1303
- var RawXml = class extends import_docx.XmlComponent {
2965
+ var RawXml = class extends import_docx2.XmlComponent {
1304
2966
  constructor(tag, attributes = {}, text = null) {
1305
2967
  super(tag);
1306
2968
  if (Object.keys(attributes).length > 0)
@@ -1310,85 +2972,227 @@ var RawXml = class extends import_docx.XmlComponent {
1310
2972
  }
1311
2973
  };
1312
2974
  function renderCodeHighlighting(code, lang) {
1313
- const grammar = import_prismjs.default.languages[lang.trim().toLowerCase()];
2975
+ const language = lang.trim().toLowerCase();
2976
+ const grammar = import_prismjs.default.languages[language];
1314
2977
  if (!grammar) return null;
1315
2978
  const themeColors = {
1316
2979
  // shared
1317
2980
  "plain": "000000",
1318
2981
  "comment": "008000",
2982
+ "hashbang": "008000",
2983
+ "shebang": "008000",
1319
2984
  "punctuation": "000000",
1320
2985
  "operator": "000000",
2986
+ "script": "000000",
2987
+ "script-punctuation": "000000",
2988
+ "expression": "000000",
2989
+ "interpolation": "000000",
1321
2990
  // keywords & control flow
1322
2991
  "keyword": "0000ff",
2992
+ "control-flow": "af00db",
1323
2993
  "boolean": "0000ff",
1324
- "builtin": "0000ff",
2994
+ "null": "0000ff",
2995
+ "builtin": "267f99",
1325
2996
  "important": "0000ff",
2997
+ // "instruction": "0000ff",
2998
+ // "directive": "0000ff",
2999
+ "directive-hash": "0000ff",
3000
+ "macro": "0000ff",
3001
+ "macro-name": "0000ff",
3002
+ "rule": "0000ff",
1326
3003
  // literals
1327
- "string": lang === "css" ? "0451a5" : lang === "json" ? "a31515" : "a31515",
1328
- "number": "098658",
1329
- "constant": "0000ff",
1330
- "symbol": "0000ff",
3004
+ "string": "a31515",
3005
+ "template-string": "a31515",
3006
+ "template-punctuation": "a31515",
3007
+ "string-literal": "a31515",
1331
3008
  "char": "a31515",
3009
+ "number": "098658",
3010
+ "datetime": "098658",
3011
+ "constant": "0070c1",
3012
+ "symbol": "0070c1",
3013
+ "scalar": "0000ff",
3014
+ "conversion-option": "0000ff",
1332
3015
  // identifiers
1333
- "class-name": lang === "js" || lang === "ts" ? "267f99" : "0451a5",
1334
- "function": "0451a5",
1335
- "variable": "000000",
1336
- "namespace": "000000",
1337
- "property": lang === "css" ? "e50000" : "0451a5",
3016
+ "class-name": "267f99",
3017
+ "class-name-definition": "267f99",
3018
+ "type-definition": "267f99",
3019
+ "return-type": "267f99",
3020
+ "attribute": "267f99",
3021
+ "attribute-class-name": "267f99",
3022
+ "annotation": "267f99",
3023
+ "decorator": "267f99",
3024
+ "namespace": "267f99",
3025
+ "double-colon": "267f99",
3026
+ "function": "795e26",
3027
+ "function-definition": "795e26",
3028
+ "method-definition": "795e26",
3029
+ "variable": "001080",
3030
+ "parameter": "001080",
3031
+ "environment": "001080",
3032
+ "assign-left": "001080",
3033
+ "property": language === "css" ? "e50000" : language === "json" ? "0451a5" : "001080",
3034
+ "key": "0451a5",
3035
+ "package": "000000",
3036
+ "lifetime-annotation": "0000ff",
1338
3037
  // markup / HTML / XML
1339
- "tag": lang === "html" || lang === "xml" ? "800000" : "0000ff",
3038
+ "tag": "800000",
1340
3039
  "selector": "800000",
1341
3040
  "attr-name": "e50000",
1342
- "attr-value": "a31515",
3041
+ "attr-value": "0000ff",
1343
3042
  "entity": "800000",
1344
3043
  "doctype": "808080",
3044
+ "doctype-tag": "808080",
3045
+ "name": "808080",
1345
3046
  "cdata": "808080",
1346
3047
  "prolog": "808080",
3048
+ "delimiter": language === "php" ? "800000" : "a31515",
1347
3049
  // CSS specific
1348
3050
  "atrule": "0000ff",
1349
3051
  "url": "0451a5",
1350
3052
  // regex
1351
- "regex": "811f3f"
3053
+ "regex": "811f3f",
3054
+ "regex-delimiter": "811f3f",
3055
+ "regex-source": "811f3f",
3056
+ "regex-flags": "0000ff",
3057
+ "interpolation-punctuation": "0000ff",
3058
+ // Markdown
3059
+ "title": "800000",
3060
+ "blockquote": "0451a5",
3061
+ "list": "0451a5",
3062
+ "bold": "000080",
3063
+ "italic": "800080",
3064
+ "code": "800000",
3065
+ "code-snippet": "800000",
3066
+ "code-block": "800000",
3067
+ "code-language": "0000ff",
3068
+ "inserted": "098658",
3069
+ "deleted": "a31515",
3070
+ "strike": "000000",
3071
+ "hr": "800000"
1352
3072
  };
3073
+ const controlFlowKeywords = /* @__PURE__ */ new Set([
3074
+ "if",
3075
+ "else",
3076
+ "elif",
3077
+ "elseif",
3078
+ "unless",
3079
+ "then",
3080
+ "switch",
3081
+ "case",
3082
+ "default",
3083
+ "when",
3084
+ "match",
3085
+ "for",
3086
+ "foreach",
3087
+ "while",
3088
+ "do",
3089
+ "until",
3090
+ "loop",
3091
+ "break",
3092
+ "continue",
3093
+ "return",
3094
+ "goto",
3095
+ "throw",
3096
+ "throws",
3097
+ "try",
3098
+ "catch",
3099
+ "except",
3100
+ "finally",
3101
+ "rescue",
3102
+ "ensure",
3103
+ "await",
3104
+ "yield",
3105
+ "new",
3106
+ "delete",
3107
+ "in",
3108
+ "of",
3109
+ "instanceof"
3110
+ ]);
1353
3111
  const tokens = import_prismjs.default.tokenize(code, grammar);
1354
3112
  return tokensToParagraphs(tokens);
1355
3113
  function tokensToParagraphs(tokens2) {
1356
3114
  const paragraphs = [];
1357
3115
  let currentRuns = [];
1358
- function addText(text, type) {
3116
+ const plainStyle = { color: themeColors.plain, bold: false, italics: false, strike: false };
3117
+ function addText(text, style) {
1359
3118
  const lines = text.split("\n");
1360
3119
  lines.forEach((line, index) => {
1361
3120
  currentRuns.push(
1362
- new import_docx.TextRun({
3121
+ new import_docx2.TextRun({
1363
3122
  text: line,
1364
- color: themeColors[type] || themeColors["plain"],
1365
- bold: type === "bold",
1366
- italics: type === "italic"
3123
+ color: style.color,
3124
+ bold: style.bold,
3125
+ italics: style.italics,
3126
+ strike: style.strike
1367
3127
  })
1368
3128
  );
1369
3129
  if (index < lines.length - 1) {
1370
- paragraphs.push(new import_docx.Paragraph({ children: currentRuns, style: STYLE_code }));
3130
+ paragraphs.push(new import_docx2.Paragraph({ children: currentRuns, style: STYLE_code }));
1371
3131
  currentRuns = [];
1372
3132
  }
1373
3133
  });
1374
3134
  }
1375
- function process2(token, parentType = "plain") {
3135
+ function process2(token, parentStyle = plainStyle) {
1376
3136
  if (typeof token === "string")
1377
- addText(token, parentType);
1378
- else if (Array.isArray(token.content))
1379
- token.content.forEach((t) => process2(t, token.type));
1380
- else if (typeof token.content === "string")
1381
- addText(token.content, token.type);
1382
- else
1383
- process2(token.content, token.type);
3137
+ addText(token, parentStyle);
3138
+ else {
3139
+ const aliases = typeof token.alias == "string" ? [token.alias] : token.alias || [];
3140
+ const types = [token.type, ...aliases];
3141
+ const colorType = types.find((type) => themeColors[type]);
3142
+ const isControlFlow = token.type == "keyword" && typeof token.content == "string" && controlFlowKeywords.has(token.content);
3143
+ const inheritPunctuation = token.type == "punctuation" && parentStyle.color != themeColors.plain;
3144
+ const style = {
3145
+ color: isControlFlow ? themeColors["control-flow"] : inheritPunctuation ? parentStyle.color : colorType ? themeColors[colorType] : parentStyle.color,
3146
+ bold: parentStyle.bold || types.includes("bold") || types.includes("important") || types.includes("title"),
3147
+ italics: parentStyle.italics || types.includes("italic"),
3148
+ strike: parentStyle.strike || types.includes("strike")
3149
+ };
3150
+ if (Array.isArray(token.content))
3151
+ token.content.forEach((t) => process2(t, style));
3152
+ else if (typeof token.content === "string")
3153
+ addText(token.content, style);
3154
+ else
3155
+ process2(token.content, style);
3156
+ }
1384
3157
  }
1385
3158
  tokens2.forEach((t) => process2(t));
1386
3159
  if (currentRuns.length > 0) {
1387
- paragraphs.push(new import_docx.Paragraph({ children: currentRuns, style: STYLE_code }));
3160
+ paragraphs.push(new import_docx2.Paragraph({ children: currentRuns, style: STYLE_code }));
1388
3161
  }
1389
3162
  return paragraphs;
1390
3163
  }
1391
3164
  }
3165
+ function estimateNumberWidthPt(text, fontSizePt) {
3166
+ const charWidths = {
3167
+ ".": 0.25,
3168
+ ",": 0.25,
3169
+ "-": 0.333,
3170
+ "(": 0.333,
3171
+ ")": 0.333,
3172
+ " ": 0.25,
3173
+ "a": 0.444,
3174
+ "b": 0.5,
3175
+ "c": 0.444,
3176
+ "d": 0.5,
3177
+ "e": 0.444,
3178
+ "A": 0.722,
3179
+ "B": 0.667,
3180
+ "C": 0.667,
3181
+ "D": 0.722,
3182
+ "E": 0.611,
3183
+ "\u0430": 0.5,
3184
+ "\u0431": 0.5,
3185
+ "\u0432": 0.5,
3186
+ "\u0433": 0.5,
3187
+ "\u0434": 0.5,
3188
+ "\u0410": 0.722,
3189
+ "\u0411": 0.667,
3190
+ "\u0412": 0.667,
3191
+ "\u0413": 0.611,
3192
+ "\u0414": 0.722
3193
+ };
3194
+ return [...text].reduce((width, char) => width + (charWidths[char] ?? 0.5) * fontSizePt, 0);
3195
+ }
1392
3196
  function genXml_app({ totalTime }) {
1393
3197
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1394
3198
  <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
@@ -1396,23 +3200,32 @@ function genXml_app({ totalTime }) {
1396
3200
  </Properties>
1397
3201
  `;
1398
3202
  }
3203
+ function escapeXml(value) {
3204
+ return value.replaceAll(/[<>&"']/g, (ch) => ({
3205
+ "<": "&lt;",
3206
+ ">": "&gt;",
3207
+ "&": "&amp;",
3208
+ '"': "&quot;",
3209
+ "'": "&apos;"
3210
+ })[ch]);
3211
+ }
1399
3212
  function genXml_core({ title, creator, createdAt, modifiedAt }) {
1400
3213
  if (!createdAt) createdAt = /* @__PURE__ */ new Date();
1401
3214
  if (!modifiedAt) modifiedAt = /* @__PURE__ */ new Date();
1402
3215
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1403
3216
  <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">
1404
- <dc:title>${title || "Document"}</dc:title>
1405
- <dc:creator>${creator || "Student"}</dc:creator>
1406
- <cp:lastModifiedBy>${creator || "Student"}</cp:lastModifiedBy>
3217
+ <dc:title>${escapeXml(title || "Document")}</dc:title>
3218
+ <dc:creator>${escapeXml(creator || "Student")}</dc:creator>
3219
+ <cp:lastModifiedBy>${escapeXml(creator || "Student")}</cp:lastModifiedBy>
1407
3220
  <dcterms:created xsi:type="dcterms:W3CDTF">${createdAt.toISOString()}</dcterms:created>
1408
3221
  <dcterms:modified xsi:type="dcterms:W3CDTF">${modifiedAt.toISOString()}</dcterms:modified>
1409
3222
  </cp:coreProperties>`;
1410
3223
  }
1411
3224
  function genXml_style(assets, doc) {
1412
- let xml = fs3.readFileSync(import_path2.default.join(assets, "styles.xml"), { encoding: "utf8" });
3225
+ let xml = fs4.readFileSync(import_path3.default.join(assets, "styles.xml"), { encoding: "utf8" });
1413
3226
  xml = editStyle(`<w:style w:type="paragraph" w:default="1" w:styleId="a2">`, (xml2) => {
1414
3227
  xml2 = replaceTag(xml2, `<w:spacing w:line="${doc.text.line_spacing * 240}" w:lineRule="auto" w:after="${doc.text.spacing.after * 20}"/>`);
1415
- xml2 = replaceTag(xml2, `<w:ind w:firstLine="${(0, import_docx.convertMillimetersToTwip)(doc.text.indent * 10)}"/>`);
3228
+ xml2 = replaceTag(xml2, `<w:ind w:firstLine="${(0, import_docx2.convertMillimetersToTwip)(doc.text.indent * 10)}"/>`);
1416
3229
  xml2 = replaceTag(xml2, `<w:sz w:val="${doc.text.size * 2}"/>`);
1417
3230
  return xml2;
1418
3231
  });
@@ -1434,7 +3247,33 @@ function genXml_style(assets, doc) {
1434
3247
  xml2 = addrPrStyle(xml2, doc.table.title.style == "bold" ? "<w:b/>" : "<w:i/>");
1435
3248
  return xml2;
1436
3249
  });
3250
+ const admonitionTypes = ["note", "info", "tip", "warning", "danger"];
3251
+ for (const type of admonitionTypes) {
3252
+ const suffix = type == "note" ? "" : type;
3253
+ const styleId = `xAdmonition${suffix}`;
3254
+ const styleTag = `<w:style w:type="paragraph" w:customStyle="1" w:styleId="${styleId}">`;
3255
+ const style = doc.admonition[type];
3256
+ xml = editStyle(styleTag, (xml2) => {
3257
+ xml2 = replaceTagOrInsertAfter(xml2, "<w:pPr>", `<w:spacing w:before="${style.spacing.before * 20}" w:after="${style.spacing.after * 20}"/>`);
3258
+ xml2 = replaceTagOrInsertAfter(xml2, "<w:pPr>", `<w:ind w:left="${(0, import_docx2.convertMillimetersToTwip)(style.indent * 10)}" w:firstLine="0"/>`);
3259
+ xml2 = replaceBorder(xml2, "top", style.padding.top, "FFFFFF", 2);
3260
+ xml2 = replaceBorder(xml2, "right", style.padding.right, "FFFFFF", 2);
3261
+ xml2 = replaceBorder(xml2, "bottom", style.padding.bottom, "FFFFFF", 2);
3262
+ xml2 = replaceBorder(xml2, "left", style.padding.left, style.color, Math.max(1, Math.round(style.bar_width * 8)));
3263
+ xml2 = replaceTagOrInsertAfter(xml2, "<w:pPr>", `<w:shd w:val="clear" w:color="auto" w:fill="${style.background}"/>`);
3264
+ return xml2;
3265
+ });
3266
+ }
1437
3267
  return xml;
3268
+ function replaceBorder(xml2, side, space, color, size) {
3269
+ return replaceTagOrInsertAfter(xml2, "<w:pBdr>", `<w:${side} w:val="single" w:sz="${size}" w:space="${space}" w:color="${color}"/>`);
3270
+ }
3271
+ function replaceTagOrInsertAfter(xml2, insertAfter2, tag) {
3272
+ const tagName = /<([^\s>]+)/.exec(tag)?.[1];
3273
+ if (!tagName) throw err();
3274
+ const regex = new RegExp(`<${tagName}\\b[^>]*/>`);
3275
+ return regex.test(xml2) ? xml2.replace(regex, tag) : xml2.replace(insertAfter2, `${insertAfter2}${tag}`);
3276
+ }
1438
3277
  function replaceTag(xml2, tag) {
1439
3278
  const tagName = /<([^\s]+)\b/.exec(tag)?.[1];
1440
3279
  if (!tagName) throw err();
@@ -1474,13 +3313,14 @@ function genXml_style(assets, doc) {
1474
3313
 
1475
3314
  // src/enricher.ts
1476
3315
  function enrichDoc(doc, logwarn = console.warn) {
3316
+ const warnAt = (line, message) => logwarn(`Line ${doc.mapSourceLine(line)}: ${message}`);
1477
3317
  for (let i = 0; i < doc.nodes.length; i++) {
1478
3318
  const node = doc.nodes[i];
1479
- if (node.type == "title" && node.text.toUpperCase().startsWith("\u0422\u0418\u0422\u0423\u041B\u042C\u041D\u0418\u041A")) {
1480
- doc.nodes.splice(i, 1, { type: "text", text: node.text.toUpperCase() });
1481
- doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
3319
+ if (node.type == "title" && node.level == 1 && node.text.toUpperCase().startsWith("\u0422\u0418\u0422\u0423\u041B\u042C\u041D\u0418\u041A")) {
3320
+ doc.nodes.splice(i, 1, { type: "text", text: node.text.toUpperCase(), sourceLine: node.sourceLine });
3321
+ doc.nodes.splice(i + 1, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1482
3322
  i++;
1483
- } else if (node.type == "title" && node.text.toUpperCase() == "\u0420\u0415\u0424\u0415\u0420\u0410\u0422") {
3323
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u0420\u0415\u0424\u0415\u0420\u0410\u0422") {
1484
3324
  node.level = 0;
1485
3325
  node.text = node.text.toUpperCase();
1486
3326
  const nextNode = doc.nodes[i + 1];
@@ -1488,81 +3328,83 @@ function enrichDoc(doc, logwarn = console.warn) {
1488
3328
  nextNode.noIndent = true;
1489
3329
  nextNode.text = trimEnd(nextNode.text, ".").toUpperCase();
1490
3330
  }
1491
- 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." });
3331
+ 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.", sourceLine: node.sourceLine });
1492
3332
  while (i + 1 < doc.nodes.length && doc.nodes[i + 1]?.type != "title") i++;
1493
- doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
1494
- } else if (node.type == "title" && node.text.toUpperCase() == "\u041E\u0413\u041B\u0410\u0412\u041B\u0415\u041D\u0418\u0415") {
3333
+ doc.nodes.splice(i + 1, 0, { type: "pageBreak", sourceLine: node.sourceLine });
3334
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u041E\u0413\u041B\u0410\u0412\u041B\u0415\u041D\u0418\u0415") {
1495
3335
  node.level = 0;
1496
3336
  node.text = node.text.toUpperCase();
1497
- doc.nodes.splice(i + 1, 0, { type: "tableOfContents" });
1498
- } 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") {
3337
+ doc.nodes.splice(i + 1, 0, { type: "tableOfContents", sourceLine: node.sourceLine });
3338
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u0422\u0415\u0420\u041C\u0418\u041D\u042B \u0418 \u041E\u041F\u0420\u0415\u0414\u0415\u041B\u0415\u041D\u0418\u042F") {
1499
3339
  node.center = true;
1500
3340
  node.text = node.text.toUpperCase();
1501
- 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");
3341
+ const warn = (ln) => warnAt(ln, "Wrong format of \u0422\u0415\u0420\u041C\u0418\u041D\u042B \u0418 \u041E\u041F\u0420\u0415\u0414\u0415\u041B\u0415\u041D\u0418\u042F");
1502
3342
  const list = doc.nodes[i + 1];
1503
3343
  if (list?.type != "list") {
1504
- warn();
3344
+ warn(node.sourceLine);
1505
3345
  continue;
1506
3346
  }
1507
- const rows = [tableRow("\u0422\u0435\u0440\u043C\u0438\u043D", "\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435")];
3347
+ const rows = [tableRow(list.sourceLine, "\u0422\u0435\u0440\u043C\u0438\u043D", "\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435")];
1508
3348
  const align = ["l", "l"];
1509
3349
  for (const item of list.items) {
1510
3350
  if (item.type != "listItem") {
1511
- warn();
3351
+ warn(item.sourceLine);
1512
3352
  continue;
1513
3353
  }
1514
3354
  const i2 = item.text.indexOf(":");
1515
3355
  if (i2 < 0) {
1516
- warn();
3356
+ warn(item.sourceLine);
1517
3357
  continue;
1518
3358
  }
1519
- rows.push(tableRow(item.text.slice(0, i2).trim(), item.text.slice(i2 + 1).trim()));
3359
+ rows.push(tableRow(item.sourceLine, item.text.slice(0, i2).trim(), item.text.slice(i2 + 1).trim()));
1520
3360
  }
1521
- 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." });
1522
- doc.nodes.splice(i + 2, 0, { type: "table", align, rows, normalFontSize: true, tags: ["definitions_table"] });
1523
- doc.nodes.splice(i + 3, 0, { type: "pageBreak" });
1524
- } 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") {
3361
+ 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.", sourceLine: node.sourceLine });
3362
+ doc.nodes.splice(i + 2, 0, { type: "table", align, rows, normalFontSize: true, tags: ["definitions_table"], sourceLine: node.sourceLine });
3363
+ doc.nodes.splice(i + 3, 0, { type: "pageBreak", sourceLine: node.sourceLine });
3364
+ } else if (node.type == "title" && node.level == 1 && 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") {
1525
3365
  node.center = true;
1526
3366
  node.text = node.text.toUpperCase();
1527
- 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");
3367
+ const warn = (ln) => warnAt(ln, "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");
1528
3368
  const list = doc.nodes[i + 1];
1529
3369
  if (list?.type != "list") {
1530
- warn();
3370
+ warn(node.sourceLine);
1531
3371
  continue;
1532
3372
  }
1533
3373
  const items = [];
1534
3374
  for (const item of list.items) {
1535
3375
  if (item.type != "listItem") {
1536
- warn();
3376
+ warn(item.sourceLine);
1537
3377
  continue;
1538
3378
  }
1539
- items.push({ type: "text", text: trimEnd(item.text, "."), noIndent: true, noMargin: true });
3379
+ items.push({ type: "text", text: trimEnd(item.text, "."), noIndent: true, noMargin: true, sourceLine: item.sourceLine });
1540
3380
  }
1541
- 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." });
1542
- doc.nodes.splice(i + 2, 0, { type: "pageBreak" });
3381
+ 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.", sourceLine: node.sourceLine });
3382
+ doc.nodes.splice(i + 2, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1543
3383
  doc.nodes.splice(i + 2, 0, ...items);
1544
- } else if (node.type == "title" && node.text.toUpperCase() == "\u0412\u0412\u0415\u0414\u0415\u041D\u0418\u0415") {
3384
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u0412\u0412\u0415\u0414\u0415\u041D\u0418\u0415") {
1545
3385
  node.center = true;
1546
3386
  node.text = node.text.toUpperCase();
1547
3387
  for (let j = i + 1; j < doc.nodes.length; j++) {
1548
3388
  const node2 = doc.nodes[j];
1549
3389
  if (node2?.type == "title") {
1550
- doc.nodes.splice(j, 0, { type: "pageBreak" });
3390
+ doc.nodes.splice(j, 0, { type: "pageBreak", sourceLine: -1 });
1551
3391
  break;
1552
3392
  }
1553
3393
  }
1554
- } else if (node.type == "title" && node.text.toUpperCase() == "\u0417\u0410\u041A\u041B\u042E\u0427\u0415\u041D\u0418\u0415") {
3394
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u0417\u0410\u041A\u041B\u042E\u0427\u0415\u041D\u0418\u0415") {
1555
3395
  node.center = true;
1556
3396
  node.text = node.text.toUpperCase();
1557
- doc.nodes.splice(i, 0, { type: "pageBreak" });
3397
+ doc.nodes.splice(i, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1558
3398
  i++;
1559
- } 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") {
3399
+ } else if (node.type == "title" && node.level == 1 && 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") {
1560
3400
  node.center = true;
1561
3401
  node.text = node.text.toUpperCase();
1562
- doc.nodes.splice(i++, 0, { type: "pageBreak" });
3402
+ doc.nodes.splice(i++, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1563
3403
  const nextNode = doc.nodes[i + 1];
1564
3404
  if (nextNode?.type == "list") {
1565
3405
  nextNode.alternativeStyle = true;
3406
+ nextNode.tags = nextNode.tags || [];
3407
+ nextNode.tags.push("sources");
1566
3408
  i++;
1567
3409
  continue;
1568
3410
  }
@@ -1571,35 +3413,38 @@ function enrichDoc(doc, logwarn = console.warn) {
1571
3413
  mark: ".",
1572
3414
  startIndex: 1,
1573
3415
  alternativeStyle: true,
3416
+ tags: ["sources"],
1574
3417
  ordered: true,
1575
- items: []
3418
+ items: [],
3419
+ sourceLine: node.sourceLine + 1
1576
3420
  };
1577
3421
  const startI = i + 1;
1578
3422
  while (true) {
1579
3423
  const textNode = doc.nodes[i + 1];
1580
3424
  if (textNode?.type != "text") break;
1581
3425
  const items = textNode.text.split(/\n\s*(?=\[[a-zA-Zа-яА-ЯёЁ_\d]+\])/);
3426
+ let sourceLine = textNode.sourceLine;
1582
3427
  for (const item of items)
1583
- list.items.push({ type: "listItem", text: item });
3428
+ list.items.push({ type: "listItem", text: item, sourceLine: sourceLine++ });
1584
3429
  i++;
1585
3430
  }
1586
3431
  if (list.items.length > 0)
1587
3432
  doc.nodes.splice(startI, i - startI + 1, list);
1588
- } else if (node.type == "title" && node.text.toUpperCase() == "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u042F") {
3433
+ } else if (node.type == "title" && node.level == 1 && node.text.toUpperCase() == "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u042F") {
1589
3434
  node.level = 0;
1590
3435
  node.center = true;
1591
3436
  node.text = node.text.toUpperCase();
1592
- doc.nodes.splice(i++, 0, { type: "pageBreak" });
3437
+ doc.nodes.splice(i++, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1593
3438
  for (let j = i + 1; j < doc.nodes.length; j++) {
1594
3439
  const node2 = doc.nodes[j];
1595
3440
  if (node2.type == "title") {
1596
- doc.nodes.splice(i++ + 1, 0, { type: "text", text: "\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 " + node2.text.replace("]", "].") });
3441
+ doc.nodes.splice(i++ + 1, 0, { type: "text", text: "\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 " + node2.text.replace("]", "]."), sourceLine: node2.sourceLine });
1597
3442
  j++;
1598
3443
  node2.level = 1;
1599
3444
  const splitI = node2.text.indexOf("]");
1600
- doc.nodes.splice(j++, 0, { type: "pageBreak" });
3445
+ doc.nodes.splice(j++, 0, { type: "pageBreak", sourceLine: node2.sourceLine });
1601
3446
  if (splitI >= 0) {
1602
- doc.nodes.splice(j++ + 1, 0, { type: "text", text: node2.text.slice(splitI + 1), center: true });
3447
+ doc.nodes.splice(j++ + 1, 0, { type: "text", text: node2.text.slice(splitI + 1), center: true, sourceLine: node2.sourceLine });
1603
3448
  node2.text = "\u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u0415 " + node2.text.slice(0, splitI + 1);
1604
3449
  node2.center = true;
1605
3450
  }
@@ -1635,11 +3480,11 @@ function enrichDoc(doc, logwarn = console.warn) {
1635
3480
  } else if (node.type == "externalDoc") {
1636
3481
  const nextNode = doc.nodes[i + 1];
1637
3482
  if (nextNode && nextNode?.type != "externalDoc" && nextNode?.type != "pageBreak" && nextNode?.type != "sectionBreak") {
1638
- doc.nodes.splice(i + 1, 0, { type: "pageBreak" });
3483
+ doc.nodes.splice(i + 1, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1639
3484
  }
1640
3485
  const prevNode = doc.nodes[i - 1];
1641
3486
  if (prevNode && prevNode?.type != "externalDoc" && prevNode?.type != "pageBreak" && prevNode?.type != "sectionBreak") {
1642
- doc.nodes.splice(i, 0, { type: "pageBreak" });
3487
+ doc.nodes.splice(i, 0, { type: "pageBreak", sourceLine: node.sourceLine });
1643
3488
  i++;
1644
3489
  }
1645
3490
  }
@@ -1648,7 +3493,7 @@ function enrichDoc(doc, logwarn = console.warn) {
1648
3493
 
1649
3494
  // src/main.ts
1650
3495
  var import_child_process = require("child_process");
1651
- var import_promises3 = __toESM(require("fs/promises"));
3496
+ var import_promises4 = __toESM(require("fs/promises"));
1652
3497
  var import_fs2 = require("fs");
1653
3498
  var import_pdf_lib = require("pdf-lib");
1654
3499
 
@@ -1659,12 +3504,15 @@ function alchemist(doc, logwarn = console.warn) {
1659
3504
  codesAll: 0,
1660
3505
  imgsAll: 0,
1661
3506
  tablesAll: 0,
3507
+ formulasAll: 0,
1662
3508
  codes: 0,
1663
3509
  imgs: 0,
1664
3510
  tables: 0,
3511
+ formulas: 0,
1665
3512
  titles: { l1: 0, l2: 0, l3: 0, l4: 0, l5: 0 }
1666
3513
  };
1667
3514
  const named = {};
3515
+ const warnAt = (line, message) => logwarn(`${line ? `Line ${doc.mapSourceLine(line)}: ` : ""}${message}`);
1668
3516
  const vals = {};
1669
3517
  let lastRefI = 0;
1670
3518
  let prevNum = -1;
@@ -1681,11 +3529,13 @@ function alchemist(doc, logwarn = console.warn) {
1681
3529
  let codes = counter.codes;
1682
3530
  let imgs = counter.imgs;
1683
3531
  let tables = counter.tables;
3532
+ let formulas = counter.formulas;
1684
3533
  for (let j = i; j < doc.nodes.length && nextNum < 0; j++) {
1685
3534
  const n = doc.nodes[j];
1686
3535
  if (n.type == "code") nextNum = codes + 1;
1687
3536
  if (n.type == "image") nextNum = imgs + 1;
1688
3537
  if (n.type == "table") nextNum = tables + 1;
3538
+ if (n.type == "math") nextNum = formulas + 1;
1689
3539
  if (n.type == "title" && n.level == 1 && doc.numberingSections) {
1690
3540
  const num = getTitleNum(n);
1691
3541
  if (num) l1 = num;
@@ -1693,6 +3543,7 @@ function alchemist(doc, logwarn = console.warn) {
1693
3543
  codes = 0;
1694
3544
  imgs = 0;
1695
3545
  tables = 0;
3546
+ formulas = 0;
1696
3547
  }
1697
3548
  }
1698
3549
  nextPrefix = l1 > 0 && doc.numberingSections ? `${l1}.` : "";
@@ -1715,13 +3566,14 @@ function alchemist(doc, logwarn = console.warn) {
1715
3566
  counter.codes = 0;
1716
3567
  counter.imgs = 0;
1717
3568
  counter.tables = 0;
3569
+ counter.formulas = 0;
1718
3570
  }
1719
3571
  prefix = doc.numberingSections ? `${counter.titles.l1}.` : "";
1720
3572
  if (appendix) prefix = APPENDIX_NAME[counter.titles.l1 - 1] + ".";
1721
3573
  }
1722
3574
  }
1723
3575
  materializeNode(node);
1724
- if (node.type == "code" || node.type == "image" || node.type == "table") {
3576
+ if (node.type == "code" || node.type == "image" || node.type == "table" || node.type == "math") {
1725
3577
  if (node.type == "code") {
1726
3578
  counter.codes++;
1727
3579
  counter.codesAll++;
@@ -1734,18 +3586,27 @@ function alchemist(doc, logwarn = console.warn) {
1734
3586
  counter.tables++;
1735
3587
  counter.tablesAll++;
1736
3588
  }
3589
+ if (node.type == "math") {
3590
+ counter.formulas++;
3591
+ counter.formulasAll++;
3592
+ }
1737
3593
  prevNum = nextNum;
1738
3594
  prevPrefix = prefix;
1739
3595
  nextNum = -1;
1740
3596
  }
1741
3597
  });
3598
+ for (const value of [doc.header, doc.footer, ...doc.nodes.filter((node) => node.type == "sectionBreak").flatMap((node) => [node.header, node.footer])]) {
3599
+ if (value?.type != "content") continue;
3600
+ value.nodes.forEach(materializeNode);
3601
+ }
1742
3602
  const sourcesCount = crystallizeSources();
1743
- vals["codes"]?.forEach((f) => f(counter.codes));
1744
- vals["imgs"]?.forEach((f) => f(counter.imgs));
1745
- vals["tables"]?.forEach((f) => f(counter.tables));
3603
+ vals["codes"]?.forEach((f) => f(counter.codesAll));
3604
+ vals["imgs"]?.forEach((f) => f(counter.imgsAll));
3605
+ vals["tables"]?.forEach((f) => f(counter.tablesAll));
3606
+ vals["formulas"]?.forEach((f) => f(counter.formulasAll));
1746
3607
  vals["sources"]?.forEach((f) => f(sourcesCount));
1747
3608
  Object.entries(named).forEach(([k, v]) => {
1748
- if (v instanceof Array) logwarn(`\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 [${k}]`);
3609
+ if (v instanceof Array) v.forEach((ref) => warnAt(ref.sourceLine, `\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 [${k}]`));
1749
3610
  });
1750
3611
  if (synopsis) {
1751
3612
  synopsis.text = [
@@ -1779,7 +3640,7 @@ function alchemist(doc, logwarn = console.warn) {
1779
3640
  function materializeList(node) {
1780
3641
  node.items.forEach((item) => {
1781
3642
  if (item.type == "list") materializeList(item);
1782
- else materializeRunes(item.text, node);
3643
+ else materializeRunes(item.text, { ...node, sourceLine: item.sourceLine ?? node.sourceLine });
1783
3644
  });
1784
3645
  }
1785
3646
  function materializeTable(node) {
@@ -1827,8 +3688,9 @@ function alchemist(doc, logwarn = console.warn) {
1827
3688
  rune.text = repeat(node.level, (i2) => counter.titles[`l${i2 + 1}`]).join(".");
1828
3689
  return;
1829
3690
  }
1830
- if (type == "code" || type == "image" || type == "table") {
1831
- 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" } : (() => {
3691
+ if (type == "code" || type == "image" || type == "table" || type == "math") {
3692
+ 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" } : type == "math" ? { num: counter.formulas, text: "" } : (() => {
3693
+ type;
1832
3694
  throw new Error("switch default");
1833
3695
  })();
1834
3696
  num++;
@@ -1845,9 +3707,10 @@ function alchemist(doc, logwarn = console.warn) {
1845
3707
  nextRune.text = toCapitalCase(nextRune.text);
1846
3708
  }
1847
3709
  text = `${text} ${prefix}${num} \u2013 `;
3710
+ if (type == "math") text = `${prefix}${num}`;
1848
3711
  } else text = `${prefix}${num}`;
1849
3712
  if (v instanceof Array) v.forEach((fn) => fn.f(num, prefix));
1850
- 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`);
3713
+ else if (v && tag != "#") warnAt(node.sourceLine, `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" : type == "math" ? "\u0444\u043E\u0440\u043C\u0443\u043B\u044B" : ""} \u0443\u0436\u0435 \u0437\u0430\u043D\u044F\u0442\u043E \u0447\u0435\u043C-\u0442\u043E \u0434\u0440\u0443\u0433\u0438\u043C`);
1851
3714
  named[tag] = { n: num, prefix };
1852
3715
  rune.type = "text";
1853
3716
  rune.text = text;
@@ -1867,8 +3730,8 @@ function alchemist(doc, logwarn = console.warn) {
1867
3730
  rune.type = "text";
1868
3731
  rune.text = n < 0 ? prefix2 : `${prefix2}${applyMath(n)}`;
1869
3732
  };
1870
- if (v) v.push({ f, i: lastRefI++ });
1871
- else named[tag] = [{ f, i: lastRefI++ }];
3733
+ if (v) v.push({ f, i: lastRefI++, sourceLine: node.sourceLine });
3734
+ else named[tag] = [{ f, i: lastRefI++, sourceLine: node.sourceLine }];
1872
3735
  } else {
1873
3736
  rune.type = "text";
1874
3737
  rune.text = `${v.prefix}${applyMath(v.n)}`;
@@ -1876,21 +3739,22 @@ function alchemist(doc, logwarn = console.warn) {
1876
3739
  });
1877
3740
  }
1878
3741
  function crystallizeSources() {
1879
- const sourcesList = doc.nodes.find((node) => node.type == "list" && node.alternativeStyle);
3742
+ const sourcesList = doc.nodes.find((node) => node.type == "list" && node.tags?.includes("sources"));
1880
3743
  if (!sourcesList || sourcesList.type != "list") return 0;
1881
- const items = sourcesList.items.filter((v) => v.type == "listItem").map((v) => v.text).map((item, i) => {
3744
+ const items = sourcesList.items.filter((v) => v.type == "listItem").map((v, i) => {
3745
+ const item = v.text;
1882
3746
  const refI = item[0]?.text ? 0 : 1;
1883
3747
  const ref = item[refI];
1884
3748
  if (ref?.type != "ref") {
1885
- return { text: item, ref: "", i: 99999 + i };
3749
+ return { text: item, ref: "", i: 99999 + i, srcI: v.sourceLine };
1886
3750
  }
1887
3751
  const refs = named[ref.text];
1888
3752
  if (refs && !(refs instanceof Array)) {
1889
- 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`);
1890
- return { text: item.slice(refI + 1), ref: "", i: 99999 + i };
3753
+ warnAt(sourcesList.sourceLine, `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`);
3754
+ return { text: item.slice(refI + 1), ref: "", i: 99999 + i, srcI: v.sourceLine };
1891
3755
  }
1892
- const firstOccurrenceI = Math.min(...refs.map((v) => v.i));
1893
- return { text: item.slice(refI + 1), ref: ref.text, i: firstOccurrenceI };
3756
+ const firstOccurrenceI = Math.min(...refs.map((v2) => v2.i));
3757
+ return { text: item.slice(refI + 1), ref: ref.text, i: firstOccurrenceI, srcI: v.sourceLine };
1894
3758
  });
1895
3759
  items.sort((a, b) => a.i - b.i);
1896
3760
  const hasIdAny = items.some((it) => !!it.ref);
@@ -1900,16 +3764,17 @@ function alchemist(doc, logwarn = console.warn) {
1900
3764
  named[key] = { prefix: "", n: i + 1 };
1901
3765
  if (refs instanceof Array) {
1902
3766
  if (hasIdAny && refs.length <= 1)
1903
- 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}`);
3767
+ warnAt(item.srcI, `\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}`);
1904
3768
  refs.forEach((r) => hasIdAny ? r.f(i + 1, "") : r.f(-1, `[${i + 1}]`));
1905
3769
  }
1906
- return { type: "listItem", text: item.text };
3770
+ return { type: "listItem", text: item.text, sourceLine: item.srcI };
1907
3771
  });
1908
3772
  return sourcesList.items.length;
1909
3773
  }
1910
3774
  }
1911
3775
  function addLazyNumbering(doc) {
1912
3776
  doc.nodes.forEach((node) => {
3777
+ if (node.type == "math" && !node.title) node.title = [{ text: "(", type: "text" }, { text: "#", type: "ref" }, { text: ")", type: "text" }];
1913
3778
  const runes = node.type == "code" || node.type == "table" ? node.title : node.type == "image" ? node.text : null;
1914
3779
  if (!runes) return;
1915
3780
  if (runes.find((rune) => rune.type == "ref")) return;
@@ -1931,6 +3796,8 @@ async function render({
1931
3796
  disableMacros = false,
1932
3797
  useLibreOffice = false,
1933
3798
  checkFilesIsInsidePath = "",
3799
+ templateOptions = { allowIncludes: true, allowLoops: true },
3800
+ variables,
1934
3801
  logwarn = console.warn,
1935
3802
  loginfo = console.info,
1936
3803
  logPS = (msg) => console.log(`PS: ${msg}`),
@@ -1938,23 +3805,23 @@ async function render({
1938
3805
  signal = null
1939
3806
  }) {
1940
3807
  signal?.throwIfAborted();
1941
- const fin = import_path3.default.resolve(file);
3808
+ const fin = import_path4.default.resolve(file);
1942
3809
  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...");
1943
3810
  loginfo(`[!1] Parsing file ${fin}`);
1944
- const doc = await parseMD(fin, logwarn);
3811
+ const doc = await parseMD(fin, variables, templateOptions, checkFilesIsInsidePath, signal, logwarn);
1945
3812
  signal?.throwIfAborted();
1946
3813
  progress(10, "\u041A\u043E\u043B\u0434\u0443\u0435\u043C \u043D\u0430\u0434 \u0441\u0438\u043D\u0442\u0430\u043A\u0441\u0438\u0441\u043E\u043C...");
1947
3814
  loginfo("[!2] Processing document");
1948
3815
  enrichDoc(doc, logwarn);
1949
3816
  const runicDoc = runifyDoc(doc);
1950
3817
  alchemist(runicDoc, logwarn);
1951
- const pout = output && import_path3.default.parse(import_path3.default.resolve(output));
1952
- if (pout) await import_promises3.default.mkdir(pout.dir, { recursive: true });
1953
- const p = import_path3.default.parse(fin);
3818
+ const pout = output && import_path4.default.parse(import_path4.default.resolve(output));
3819
+ if (pout) await import_promises4.default.mkdir(pout.dir, { recursive: true });
3820
+ const p = import_path4.default.parse(fin);
1954
3821
  const fdir = p.dir;
1955
3822
  const fname = trimEnd(p.name, ".g");
1956
- const ftmp = import_path3.default.join(fdir, fname + ".tmp.docx");
1957
- const fout = pout ? import_path3.default.join(pout.dir, pout.name + ".docx") : import_path3.default.join(fdir, fname + ".docx");
3823
+ const ftmp = import_path4.default.join(fdir, fname + ".tmp.docx");
3824
+ const fout = pout ? import_path4.default.join(pout.dir, pout.name + ".docx") : import_path4.default.join(fdir, fname + ".docx");
1958
3825
  if (await checkIfFileIsBlocked(ftmp))
1959
3826
  throw new Error(`\u0417\u0430\u043A\u0440\u043E\u0439\u0442\u0435 docx \u0444\u0430\u0439\u043B. Output file is busy or locked: ${ftmp}`);
1960
3827
  if (await checkIfFileIsBlocked(fout))
@@ -1962,7 +3829,7 @@ async function render({
1962
3829
  signal?.throwIfAborted();
1963
3830
  progress(10, phrase_renderDocx());
1964
3831
  loginfo("[!3] Serializing to docx");
1965
- await serializeDocx(runicDoc, ftmp, fdir, assets, checkFilesIsInsidePath);
3832
+ await serializeDocx(runicDoc, ftmp, fdir, assets, checkFilesIsInsidePath, logwarn);
1966
3833
  let willRunMacros = !disableMacros && (renderPDF || hasReasonForRunningMacros(runicDoc));
1967
3834
  let limitedRender = false;
1968
3835
  if (process.platform != "win32" && willRunMacros && !useLibreOffice) {
@@ -1973,31 +3840,31 @@ async function render({
1973
3840
  signal?.throwIfAborted();
1974
3841
  progress(20, phrase_runMacros());
1975
3842
  loginfo("[!4] Starting macros");
1976
- const tmpfolder = import_path3.default.join(pout ? pout.dir : fdir, ".md2gost_out");
1977
- await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
3843
+ const tmpfolder = import_path4.default.join(pout ? pout.dir : fdir, ".md2gost_out");
3844
+ await import_promises4.default.rm(tmpfolder, { recursive: true, force: true });
1978
3845
  try {
1979
3846
  const macroRunner = useLibreOffice ? runUnoScript : runDocxMacro;
1980
3847
  const ok = await macroRunner(progress, logPS, logPSError, assets, fdir, ftmp, fout, renderPDF, signal);
1981
3848
  if (!ok) {
1982
- await import_promises3.default.rename(ftmp, fout);
3849
+ await import_promises4.default.rename(ftmp, fout);
1983
3850
  return { fout, err: "inPS" };
1984
3851
  }
1985
3852
  } catch (x) {
1986
3853
  if (signal?.aborted) {
1987
- await import_promises3.default.unlink(ftmp).catch(() => {
3854
+ await import_promises4.default.unlink(ftmp).catch(() => {
1988
3855
  });
1989
3856
  throw x;
1990
3857
  }
1991
- await import_promises3.default.rename(ftmp, fout);
3858
+ await import_promises4.default.rename(ftmp, fout);
1992
3859
  return { fout, err: "noPS", errS: x };
1993
3860
  }
1994
3861
  if ((0, import_fs2.existsSync)(ftmp))
1995
- await import_promises3.default.unlink(ftmp);
3862
+ await import_promises4.default.unlink(ftmp);
1996
3863
  signal?.throwIfAborted();
1997
- const errorTxt = import_path3.default.join(tmpfolder, "error.txt");
3864
+ const errorTxt = import_path4.default.join(tmpfolder, "error.txt");
1998
3865
  if ((0, import_fs2.existsSync)(errorTxt)) {
1999
- const err = await import_promises3.default.readFile(errorTxt);
2000
- await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
3866
+ const err = await import_promises4.default.readFile(errorTxt);
3867
+ await import_promises4.default.rm(tmpfolder, { recursive: true, force: true });
2001
3868
  return { fout, err: "vba", errS: `${err}` };
2002
3869
  }
2003
3870
  loginfo("[!5] Updating metadata");
@@ -2009,11 +3876,11 @@ async function render({
2009
3876
  if (!(0, import_fs2.existsSync)(tmpfolder))
2010
3877
  return { fout, err: "pdf" };
2011
3878
  try {
2012
- const files = (await import_promises3.default.readdir(tmpfolder)).sort().map((f) => import_path3.default.join(tmpfolder, f));
2013
- const pdf = pout ? import_path3.default.join(pout.dir, pout.base) : import_path3.default.join(fdir, fname + ".pdf");
3879
+ const files = (await import_promises4.default.readdir(tmpfolder)).sort().map((f) => import_path4.default.join(tmpfolder, f));
3880
+ const pdf = pout ? import_path4.default.join(pout.dir, pout.name + ".pdf") : import_path4.default.join(fdir, fname + ".pdf");
2014
3881
  await mergePDFs(files, pdf, doc, signal || void 0);
2015
- await import_promises3.default.rm(tmpfolder, { recursive: true, force: true });
2016
- if (removeIntermediateDocx && (0, import_fs2.existsSync)(fout)) await import_promises3.default.unlink(fout);
3882
+ await import_promises4.default.rm(tmpfolder, { recursive: true, force: true });
3883
+ if (removeIntermediateDocx && (0, import_fs2.existsSync)(fout)) await import_promises4.default.unlink(fout);
2017
3884
  return { fout: pdf };
2018
3885
  } catch (err) {
2019
3886
  if (signal?.aborted) throw err;
@@ -2021,7 +3888,7 @@ async function render({
2021
3888
  }
2022
3889
  }
2023
3890
  } else {
2024
- await import_promises3.default.rename(ftmp, fout);
3891
+ await import_promises4.default.rename(ftmp, fout);
2025
3892
  }
2026
3893
  loginfo(`[!7] Rendered to ${fout}`);
2027
3894
  return { fout, err: limitedRender ? "noWin" : void 0 };
@@ -2055,8 +3922,8 @@ function killProcessTree(child, wordPid) {
2055
3922
  }
2056
3923
  }
2057
3924
  function runDocxMacro(progress, log, logError, assets, cwd, fin, fout, renderPDF, signal) {
2058
- const script = import_path3.default.join(assets, "run.ps1");
2059
- const templateMacro = import_path3.default.join(assets, "template.dotm");
3925
+ const script = import_path4.default.join(assets, "run.ps1");
3926
+ const templateMacro = import_path4.default.join(assets, "template.dotm");
2060
3927
  return new Promise((res, rej) => {
2061
3928
  if (signal?.aborted)
2062
3929
  return rej(signal.reason ?? new Error("Aborted before execution started"));
@@ -2132,7 +3999,7 @@ function getPythonExecutable() {
2132
3999
  return process.env.UNO_PYTHON_PATH || "python3";
2133
4000
  }
2134
4001
  function runUnoScript(progress, log, logError, assets, cwd, fin, fout, renderPDF, signal) {
2135
- const script = process.env.MACRO_ENGINE_PATH || import_path3.default.join(assets, "macro_engine.py");
4002
+ const script = process.env.MACRO_ENGINE_PATH || import_path4.default.join(assets, "macro_engine.py");
2136
4003
  const pythonExec = getPythonExecutable();
2137
4004
  return new Promise((res, rej) => {
2138
4005
  if (signal?.aborted) {
@@ -2196,31 +4063,61 @@ function runUnoScript(progress, log, logError, assets, cwd, fin, fout, renderPDF
2196
4063
  });
2197
4064
  }
2198
4065
  async function mergePDFs(files, fout, doc, signal) {
2199
- const mergedPdf = await import_pdf_lib.PDFDocument.create();
4066
+ const pdfFiles = files.filter((file) => file.toLowerCase().endsWith(".pdf"));
4067
+ let mainPdfIndex = -1;
4068
+ for (let i = 0; i < pdfFiles.length; i++) {
4069
+ if (pdfFiles[i].toLowerCase().endsWith("-main.pdf"))
4070
+ mainPdfIndex = i;
4071
+ }
4072
+ let mergedPdf;
4073
+ if (mainPdfIndex >= 0) {
4074
+ const bytes = await import_promises4.default.readFile(pdfFiles[mainPdfIndex], { signal });
4075
+ mergedPdf = await import_pdf_lib.PDFDocument.load(bytes);
4076
+ signal?.throwIfAborted();
4077
+ let insertionIndex = 0;
4078
+ for (const file of pdfFiles.slice(0, mainPdfIndex)) {
4079
+ const sourceBytes = await import_promises4.default.readFile(file, { signal });
4080
+ const pdf = await import_pdf_lib.PDFDocument.load(sourceBytes);
4081
+ signal?.throwIfAborted();
4082
+ const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
4083
+ for (const page of pages)
4084
+ mergedPdf.insertPage(insertionIndex++, page);
4085
+ signal?.throwIfAborted();
4086
+ }
4087
+ for (const file of pdfFiles.slice(mainPdfIndex + 1)) {
4088
+ const sourceBytes = await import_promises4.default.readFile(file, { signal });
4089
+ const pdf = await import_pdf_lib.PDFDocument.load(sourceBytes);
4090
+ signal?.throwIfAborted();
4091
+ const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
4092
+ pages.forEach((page) => mergedPdf.addPage(page));
4093
+ signal?.throwIfAborted();
4094
+ }
4095
+ } else {
4096
+ mergedPdf = await import_pdf_lib.PDFDocument.create();
4097
+ for (const file of pdfFiles) {
4098
+ const bytes = await import_promises4.default.readFile(file, { signal });
4099
+ const pdf = await import_pdf_lib.PDFDocument.load(bytes);
4100
+ signal?.throwIfAborted();
4101
+ const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
4102
+ pages.forEach((page) => mergedPdf.addPage(page));
4103
+ signal?.throwIfAborted();
4104
+ }
4105
+ }
2200
4106
  if (doc?.title) mergedPdf.setTitle(doc.title, { showInWindowTitleBar: true });
2201
4107
  if (doc?.author) mergedPdf.setAuthor(doc.author);
2202
4108
  if (doc?.ctime) mergedPdf.setCreationDate(doc.ctime);
2203
4109
  if (doc?.mtime) mergedPdf.setModificationDate(doc.mtime);
2204
- for (const file of files) {
2205
- if (!file.endsWith(".pdf")) continue;
2206
- const bytes = await import_promises3.default.readFile(file, { signal });
2207
- const pdf = await import_pdf_lib.PDFDocument.load(bytes);
2208
- signal?.throwIfAborted();
2209
- const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
2210
- pages.forEach((page) => mergedPdf.addPage(page));
2211
- signal?.throwIfAborted();
2212
- }
2213
4110
  const pdfBytes = await mergedPdf.save();
2214
- await import_promises3.default.writeFile(fout, pdfBytes, { signal });
4111
+ await import_promises4.default.writeFile(fout, pdfBytes, { signal });
2215
4112
  }
2216
4113
  async function updateMetadata(docfile, doc) {
2217
- const content = await import_promises3.default.readFile(docfile);
4114
+ const content = await import_promises4.default.readFile(docfile);
2218
4115
  const zip = new import_pizzip.default(content);
2219
4116
  function replaceTag(xml, tag, value) {
2220
4117
  const regex = new RegExp(`(<${tag}\\b[^>]*>)(.*?)(</${tag}>)`, "gs");
2221
4118
  return xml.replace(
2222
4119
  regex,
2223
- (m, otag, old, ctag) => `${otag}${escapeXml(value)}${ctag}`
4120
+ (m, otag, old, ctag) => `${otag}${escapeXml2(value)}${ctag}`
2224
4121
  );
2225
4122
  }
2226
4123
  let coreXml = zip.file("docProps/core.xml").asText();
@@ -2234,8 +4131,8 @@ async function updateMetadata(docfile, doc) {
2234
4131
  appXml = replaceTag(appXml, "TotalTime", `${doc.etime || randomInt(30, 120)}`);
2235
4132
  zip.file("docProps/app.xml", appXml);
2236
4133
  const buffer = zip.generate({ type: "nodebuffer" });
2237
- await import_promises3.default.writeFile(docfile, buffer);
2238
- function escapeXml(unsafe) {
4134
+ await import_promises4.default.writeFile(docfile, buffer);
4135
+ function escapeXml2(unsafe) {
2239
4136
  return unsafe.replaceAll(/[<>&"']/g, (ch) => {
2240
4137
  switch (ch) {
2241
4138
  case "<":
@@ -2306,11 +4203,26 @@ async function renderMarkdown(config) {
2306
4203
  assert(typeof config.useLibreOffice == "boolean" || typeof config.useLibreOffice == "undefined", "useLibreOffice must be a boolean or undefined.");
2307
4204
  assert(typeof config.checkFilesIsInsidePath == "string" || config.checkFilesIsInsidePath === false || typeof config.checkFilesIsInsidePath == "undefined", "checkFilesIsInsidePath must be a string, false or undefined.");
2308
4205
  assert(typeof config.progress == "function" || typeof config.progress == "undefined", "Progress callback must be a function or undefined.");
4206
+ assert(typeof config.variables == "object" && config.variables !== null && !Array.isArray(config.variables) || typeof config.variables == "undefined", "variables must be an object or undefined.");
4207
+ assert(typeof config.templateOptions == "object" && config.templateOptions !== null && !Array.isArray(config.templateOptions) || typeof config.templateOptions == "undefined", "templateOptions must be an object or undefined.");
4208
+ if (config.templateOptions) {
4209
+ const options = config.templateOptions;
4210
+ const booleanProps = ["allowLoops", "allowIncludes"];
4211
+ const limitProps = ["maxLoopIterations", "maxTotalIterations", "maxDepth", "maxIncludeDepth", "maxIncludes", "maxFileLength", "maxTotalInputLength", "maxGeneratedLength"];
4212
+ const extraProps = getExtraProperties(options, [...booleanProps, ...limitProps]);
4213
+ assert(extraProps.length == 0, `Found unknown properties in config.templateOptions: ${extraProps.join(", ")}`);
4214
+ booleanProps.forEach(
4215
+ (p) => assert(options[p] === void 0 || typeof options[p] == "boolean", `config.templateOptions.${p} must be a boolean or undefined.`)
4216
+ );
4217
+ limitProps.forEach(
4218
+ (p) => assert(options[p] === void 0 || Number.isSafeInteger(options[p]) && options[p] >= 0, `config.templateOptions.${p} must be a non-negative safe integer or undefined.`)
4219
+ );
4220
+ }
2309
4221
  assert(config.abortSignal instanceof AbortSignal || typeof config.abortSignal == "undefined", "abortSignal must be an AbortSignal or undefined.");
2310
4222
  {
2311
4223
  const extraProps = getExtraProperties(
2312
4224
  config,
2313
- ["input", "output", "format", "keepIntermediateDocx", "disableMacros", "useLibreOffice", "progress", "logger", "abortSignal", "checkFilesIsInsidePath"]
4225
+ ["input", "output", "format", "keepIntermediateDocx", "disableMacros", "useLibreOffice", "progress", "logger", "abortSignal", "checkFilesIsInsidePath", "variables", "templateOptions"]
2314
4226
  );
2315
4227
  assert(extraProps.length == 0, `Found unknown properties in config: ${extraProps.join(", ")}`);
2316
4228
  }
@@ -2324,20 +4236,25 @@ async function renderMarkdown(config) {
2324
4236
  (p) => assert(typeof logger[p] == "function", `config.logger.${p} must be a function.`)
2325
4237
  );
2326
4238
  }
2327
- const renderPDF = config.format === "pdf" || !config.format && !!config.output?.endsWith(".pdf");
4239
+ const outputExtension = config.output && import_path5.default.extname(config.output).toLowerCase();
4240
+ const renderPDF = config.format === "pdf" || !config.format && outputExtension === ".pdf";
2328
4241
  const removeIntermediateDocx = !config.keepIntermediateDocx;
2329
4242
  const disableMacros = !!config.disableMacros;
2330
4243
  const useLibreOffice = !!config.useLibreOffice;
2331
4244
  const checkFilesIsInsidePath = config.checkFilesIsInsidePath === void 0 ? "" : config.checkFilesIsInsidePath;
2332
4245
  assert(!(disableMacros && renderPDF), "Macros must be enabled to render PDF output.");
2333
- const pin = import_path4.default.parse(import_path4.default.resolve(config.input));
4246
+ if (outputExtension && outputExtension !== ".docx" && outputExtension !== ".pdf")
4247
+ throw new TypeError("Output file extension must be either '.docx' or '.pdf'.");
4248
+ if (outputExtension && outputExtension !== (renderPDF ? ".pdf" : ".docx"))
4249
+ throw new TypeError(`Output file extension must match the selected '${renderPDF ? "pdf" : "docx"}' format.`);
4250
+ const pin = import_path5.default.parse(import_path5.default.resolve(config.input));
2334
4251
  const fname = pin.name.endsWith(".g") ? pin.name.slice(0, -2) : pin.name;
2335
4252
  let resolvedOutput = config.output;
2336
4253
  if (resolvedOutput) {
2337
- const isDir = resolvedOutput.endsWith("/") || resolvedOutput.endsWith("\\") || !import_path4.default.extname(resolvedOutput);
4254
+ const isDir = resolvedOutput.endsWith("/") || resolvedOutput.endsWith("\\") || !import_path5.default.extname(resolvedOutput);
2338
4255
  if (isDir) {
2339
4256
  const ext = renderPDF ? ".pdf" : ".docx";
2340
- resolvedOutput = import_path4.default.join(resolvedOutput, fname + ext);
4257
+ resolvedOutput = import_path5.default.join(resolvedOutput, fname + ext);
2341
4258
  }
2342
4259
  }
2343
4260
  const warnings = [];
@@ -2362,6 +4279,8 @@ async function renderMarkdown(config) {
2362
4279
  disableMacros,
2363
4280
  useLibreOffice,
2364
4281
  checkFilesIsInsidePath,
4282
+ variables: config.variables,
4283
+ templateOptions: config.templateOptions,
2365
4284
  loginfo: logger?.info,
2366
4285
  logwarn: (msg) => {
2367
4286
  logger?.warn(msg);
@@ -2377,7 +4296,6 @@ async function renderMarkdown(config) {
2377
4296
  },
2378
4297
  signal: config.abortSignal
2379
4298
  });
2380
- config.progress?.(100, "Done!");
2381
4299
  if (useLibreOffice) {
2382
4300
  if (err == "noPS") throwMDE2("noPS", `Failed to run the LibreOffice binary (soffice). Ensure LibreOffice is installed and added to your system's PATH environment variable.`);
2383
4301
  if (err == "inPS") throwMDE2("inPS", `An unexpected error occurred executing the LibreOffice conversion command. Verify that LibreOffice is properly installed, up to date, and has permission to access the target files.`);
@@ -2388,10 +4306,11 @@ async function renderMarkdown(config) {
2388
4306
  if (err == "vba") throwMDE2("vba", `Microsoft Word VBA Macro execution failed: ${errS}`);
2389
4307
  if (err == "pdf") throwMDE2("pdf", `Failed to export document to PDF.`);
2390
4308
  if (err == "noWin") throwMDE2("noWin", `Platform restriction: Extended formatting macros and PDF rendering are only supported natively on Windows systems.`);
4309
+ config.progress?.(100, "Done!");
2391
4310
  let intermediateDocxPath;
2392
4311
  if (renderPDF && !removeIntermediateDocx) {
2393
- const pout = resolvedOutput ? import_path4.default.parse(import_path4.default.resolve(resolvedOutput)) : void 0;
2394
- intermediateDocxPath = pout ? import_path4.default.join(pout.dir, pout.name + ".docx") : import_path4.default.join(pin.dir, fname + ".docx");
4312
+ const pout = resolvedOutput ? import_path5.default.parse(import_path5.default.resolve(resolvedOutput)) : void 0;
4313
+ intermediateDocxPath = pout ? import_path5.default.join(pout.dir, pout.name + ".docx") : import_path5.default.join(pin.dir, fname + ".docx");
2395
4314
  }
2396
4315
  return {
2397
4316
  filePath: fout,
@@ -2449,10 +4368,7 @@ var MDRenderError = class _MDRenderError extends Error {
2449
4368
  }
2450
4369
  };
2451
4370
  function getAssetsDir() {
2452
- if (typeof __dirname !== "undefined")
2453
- return import_path4.default.resolve(__dirname, "../assets");
2454
- const metaUrl = new Function("return import.meta.url")();
2455
- return import_path4.default.resolve(import_path4.default.dirname((0, import_url.fileURLToPath)(metaUrl)), "../assets");
4371
+ return import_path5.default.resolve(__MD2GOST_DIRNAME__, "../assets");
2456
4372
  }
2457
4373
  function getExtraProperties(configObj, allowedConfigKeys) {
2458
4374
  return Object.keys(configObj).filter(
@@ -2461,6 +4377,7 @@ function getExtraProperties(configObj, allowedConfigKeys) {
2461
4377
  }
2462
4378
  // Annotate the CommonJS export names for ESM import in node:
2463
4379
  0 && (module.exports = {
2464
- MDRenderError
4380
+ MDRenderError,
4381
+ UserInputError
2465
4382
  });
2466
4383
  //# sourceMappingURL=index.js.map