remark-docx 0.1.8 → 0.2.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/lib/index.js CHANGED
@@ -1,8 +1,6 @@
1
- 'use strict';
2
-
3
- var unistUtilVisit = require('unist-util-visit');
4
- var docx = require('docx');
5
- var unifiedLatexUtilParse = require('@unified-latex/unified-latex-util-parse');
1
+ import { visit } from 'unist-util-visit';
2
+ import { AlignmentType, LevelFormat, convertInchesToTwip, Document, Packer, Math, Paragraph, FootnoteReferenceRun, ImageRun, ExternalHyperlink, TextRun, Table, HeadingLevel, CheckBox, TableRow, TableCell, MathRun, MathRadical, MathFraction, MathSum, MathSubScript, MathSuperScript } from 'docx';
3
+ import { parseMath } from '@unified-latex/unified-latex-util-parse';
6
4
 
7
5
  /**
8
6
  * @internal
@@ -18,455 +16,128 @@ function invariant(cond, message) {
18
16
  throw new Error(message);
19
17
  }
20
18
 
21
- const hasSquareBrackets = (arg) => {
22
- return !!arg && arg.openMark === "[" && arg.closeMark === "]";
19
+ const ORDERED_LIST_REF = "ordered";
20
+ const INDENT = 0.5;
21
+ const DEFAULT_NUMBERINGS = [
22
+ {
23
+ level: 0,
24
+ format: LevelFormat.DECIMAL,
25
+ text: "%1.",
26
+ alignment: AlignmentType.START,
27
+ },
28
+ {
29
+ level: 1,
30
+ format: LevelFormat.DECIMAL,
31
+ text: "%2.",
32
+ alignment: AlignmentType.START,
33
+ style: {
34
+ paragraph: {
35
+ indent: { start: convertInchesToTwip(INDENT * 1) },
36
+ },
37
+ },
38
+ },
39
+ {
40
+ level: 2,
41
+ format: LevelFormat.DECIMAL,
42
+ text: "%3.",
43
+ alignment: AlignmentType.START,
44
+ style: {
45
+ paragraph: {
46
+ indent: { start: convertInchesToTwip(INDENT * 2) },
47
+ },
48
+ },
49
+ },
50
+ {
51
+ level: 3,
52
+ format: LevelFormat.DECIMAL,
53
+ text: "%4.",
54
+ alignment: AlignmentType.START,
55
+ style: {
56
+ paragraph: {
57
+ indent: { start: convertInchesToTwip(INDENT * 3) },
58
+ },
59
+ },
60
+ },
61
+ {
62
+ level: 4,
63
+ format: LevelFormat.DECIMAL,
64
+ text: "%5.",
65
+ alignment: AlignmentType.START,
66
+ style: {
67
+ paragraph: {
68
+ indent: { start: convertInchesToTwip(INDENT * 4) },
69
+ },
70
+ },
71
+ },
72
+ {
73
+ level: 5,
74
+ format: LevelFormat.DECIMAL,
75
+ text: "%6.",
76
+ alignment: AlignmentType.START,
77
+ style: {
78
+ paragraph: {
79
+ indent: { start: convertInchesToTwip(INDENT * 5) },
80
+ },
81
+ },
82
+ },
83
+ ];
84
+ const createFootnoteRegistry = () => {
85
+ const idToInternalId = new Map();
86
+ const defs = new Map();
87
+ const getId = (id) => {
88
+ let internalId = idToInternalId.get(id);
89
+ if (internalId == null) {
90
+ idToInternalId.set(id, (internalId = idToInternalId.size + 1));
91
+ }
92
+ return internalId;
93
+ };
94
+ return {
95
+ ref: (id) => {
96
+ return getId(id);
97
+ },
98
+ def: (id, def) => {
99
+ const internalId = getId(id);
100
+ defs.set(internalId, def);
101
+ },
102
+ footnotes: () => {
103
+ return defs.entries().reduce((acc, [key, def]) => {
104
+ acc[key] = def;
105
+ return acc;
106
+ }, {});
107
+ },
108
+ };
23
109
  };
24
- const hasCurlyBrackets = (arg) => {
25
- return !!arg && arg.openMark === "{" && arg.closeMark === "}";
110
+ const createNumberingRegistry = () => {
111
+ let counter = 1;
112
+ return {
113
+ create: () => {
114
+ return `${ORDERED_LIST_REF}-${counter++}`;
115
+ },
116
+ getAll: () => {
117
+ return Array.from({ length: counter }, (_, i) => ({
118
+ reference: `${ORDERED_LIST_REF}-${i}`,
119
+ levels: DEFAULT_NUMBERINGS,
120
+ }));
121
+ },
122
+ };
26
123
  };
27
- const mapString = (s) => new docx.MathRun(s);
28
- const mapMacro = (n, runs) => {
29
- var _a, _b, _c, _d, _e, _f, _g, _h;
30
- switch (n.content) {
31
- case "#":
32
- return mapString("#");
33
- case "$":
34
- return mapString("$");
35
- case "%":
36
- return mapString("%");
37
- case "&":
38
- return mapString("&");
39
- case "textasciitilde":
40
- return mapString("~");
41
- case "textasciicircum":
42
- return mapString("^");
43
- case "textbackslash":
44
- return mapString("∖");
45
- case "{":
46
- return mapString("{");
47
- case "}":
48
- return mapString("}");
49
- case "textbar":
50
- return mapString("|");
51
- case "textless":
52
- return mapString("<");
53
- case "textgreater":
54
- return mapString(">");
55
- case "neq":
56
- return mapString("≠");
57
- case "sim":
58
- return mapString("∼");
59
- case "simeq":
60
- return mapString("≃");
61
- case "approx":
62
- return mapString("≈");
63
- case "fallingdotseq":
64
- return mapString("≒");
65
- case "risingdotseq":
66
- return mapString("≓");
67
- case "equiv":
68
- return mapString("≡");
69
- case "geq":
70
- return mapString("≥");
71
- case "geqq":
72
- return mapString("≧");
73
- case "leq":
74
- return mapString("≤");
75
- case "leqq":
76
- return mapString("≦");
77
- case "gg":
78
- return mapString("≫");
79
- case "ll":
80
- return mapString("≪");
81
- case "times":
82
- return mapString("×");
83
- case "div":
84
- return mapString("÷");
85
- case "pm":
86
- return mapString("±");
87
- case "mp":
88
- return mapString("∓");
89
- case "oplus":
90
- return mapString("⊕");
91
- case "ominus":
92
- return mapString("⊖");
93
- case "otimes":
94
- return mapString("⊗");
95
- case "oslash":
96
- return mapString("⊘");
97
- case "circ":
98
- return mapString("∘");
99
- case "cdot":
100
- return mapString("⋅");
101
- case "bullet":
102
- return mapString("∙");
103
- case "ltimes":
104
- return mapString("⋉");
105
- case "rtimes":
106
- return mapString("⋊");
107
- case "in":
108
- return mapString("∈");
109
- case "ni":
110
- return mapString("∋");
111
- case "notin":
112
- return mapString("∉");
113
- case "subset":
114
- return mapString("⊂");
115
- case "supset":
116
- return mapString("⊃");
117
- case "subseteq":
118
- return mapString("⊆");
119
- case "supseteq":
120
- return mapString("⊇");
121
- case "nsubseteq":
122
- return mapString("⊈");
123
- case "nsupseteq":
124
- return mapString("⊉");
125
- case "subsetneq":
126
- return mapString("⊊");
127
- case "supsetneq":
128
- return mapString("⊋");
129
- case "cap":
130
- return mapString("∩");
131
- case "cup":
132
- return mapString("∪");
133
- case "emptyset":
134
- return mapString("∅");
135
- case "infty":
136
- return mapString("∞");
137
- case "partial":
138
- return mapString("∂");
139
- case "aleph":
140
- return mapString("ℵ");
141
- case "hbar":
142
- return mapString("ℏ");
143
- case "wp":
144
- return mapString("℘");
145
- case "Re":
146
- return mapString("ℜ");
147
- case "Im":
148
- return mapString("ℑ");
149
- case "alpha":
150
- return mapString("α");
151
- case "beta":
152
- return mapString("β");
153
- case "gamma":
154
- return mapString("γ");
155
- case "delta":
156
- return mapString("δ");
157
- case "epsilon":
158
- return mapString("ϵ");
159
- case "zeta":
160
- return mapString("ζ");
161
- case "eta":
162
- return mapString("η");
163
- case "theta":
164
- return mapString("θ");
165
- case "iota":
166
- return mapString("ι");
167
- case "kappa":
168
- return mapString("κ");
169
- case "lambda":
170
- return mapString("λ");
171
- case "eta":
172
- return mapString("η");
173
- case "mu":
174
- return mapString("μ");
175
- case "nu":
176
- return mapString("ν");
177
- case "xi":
178
- return mapString("ξ");
179
- case "pi":
180
- return mapString("π");
181
- case "rho":
182
- return mapString("ρ");
183
- case "sigma":
184
- return mapString("σ");
185
- case "tau":
186
- return mapString("τ");
187
- case "upsilon":
188
- return mapString("υ");
189
- case "phi":
190
- return mapString("ϕ");
191
- case "chi":
192
- return mapString("χ");
193
- case "psi":
194
- return mapString("ψ");
195
- case "omega":
196
- return mapString("ω");
197
- case "varepsilon":
198
- return mapString("ε");
199
- case "vartheta":
200
- return mapString("ϑ");
201
- case "varrho":
202
- return mapString("ϱ");
203
- case "varsigma":
204
- return mapString("ς");
205
- case "varphi":
206
- return mapString("φ");
207
- case "Gamma":
208
- return mapString("Γ");
209
- case "Delta":
210
- return mapString("Δ");
211
- case "Theta":
212
- return mapString("Θ");
213
- case "Lambda":
214
- return mapString("Λ");
215
- case "Xi":
216
- return mapString("Ξ");
217
- case "Pi":
218
- return mapString("Π");
219
- case "Sigma":
220
- return mapString("Σ");
221
- case "Upsilon":
222
- return mapString("Υ");
223
- case "Phi":
224
- return mapString("Φ");
225
- case "Psi":
226
- return mapString("Ψ");
227
- case "Omega":
228
- return mapString("Ω");
229
- case "newline":
230
- case "\\":
231
- // line break
232
- return false;
233
- case "^": {
234
- const prev = runs.pop();
235
- if (!prev)
236
- break;
237
- return new docx.MathSuperScript({
238
- children: [prev],
239
- superScript: mapGroup((_c = (_b = (_a = n.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) !== null && _c !== void 0 ? _c : []),
240
- });
241
- }
242
- case "_": {
243
- const prev = runs.pop();
244
- if (!prev)
245
- break;
246
- return new docx.MathSubScript({
247
- children: [prev],
248
- subScript: mapGroup((_f = (_e = (_d = n.args) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.content) !== null && _f !== void 0 ? _f : []),
249
- });
250
- }
251
- case "hat":
252
- // TODO: implement
253
- break;
254
- case "widehat":
255
- // TODO: implement
256
- break;
257
- case "sum": {
258
- // TODO: support superscript and subscript
259
- return new docx.MathSum({
260
- children: [],
261
- });
262
- }
263
- case "int":
264
- return mapString("∫");
265
- case "frac":
266
- case "tfrac":
267
- case "dfrac": {
268
- const args = (_g = n.args) !== null && _g !== void 0 ? _g : [];
269
- if (args.length === 2 &&
270
- hasCurlyBrackets(args[0]) &&
271
- hasCurlyBrackets(args[1])) {
272
- return new docx.MathFraction({
273
- numerator: mapGroup(args[0].content),
274
- denominator: mapGroup(args[1].content),
275
- });
276
- }
277
- break;
278
- }
279
- case "sqrt": {
280
- const args = (_h = n.args) !== null && _h !== void 0 ? _h : [];
281
- if (args.length === 1 && hasCurlyBrackets(args[0])) {
282
- return new docx.MathRadical({
283
- children: mapGroup(args[0].content),
284
- });
285
- }
286
- if (args.length === 2 &&
287
- hasSquareBrackets(args[0]) &&
288
- hasCurlyBrackets(args[1])) {
289
- return new docx.MathRadical({
290
- children: mapGroup(args[1].content),
291
- degree: mapGroup(args[0].content),
292
- });
293
- }
294
- break;
295
- }
296
- }
297
- return mapString(n.content);
298
- };
299
- const mapGroup = (nodes) => {
300
- const group = [];
301
- for (const c of nodes) {
302
- group.push(...(mapNode(c, group) || []));
303
- }
304
- return group;
305
- };
306
- const mapNode = (n, runs) => {
307
- switch (n.type) {
308
- case "root":
309
- break;
310
- case "string":
311
- return [mapString(n.content)];
312
- case "whitespace":
313
- break;
314
- case "parbreak":
315
- break;
316
- case "comment":
317
- break;
318
- case "macro":
319
- const run = mapMacro(n, runs);
320
- if (!run) {
321
- // line break
322
- return false;
323
- }
324
- else {
325
- return [run];
326
- }
327
- case "environment":
328
- case "mathenv":
329
- break;
330
- case "verbatim":
331
- break;
332
- case "inlinemath":
333
- break;
334
- case "displaymath":
335
- break;
336
- case "group":
337
- return mapGroup(n.content);
338
- case "verb":
339
- break;
340
- default:
341
- unreachable();
342
- }
343
- return [];
344
- };
345
- /**
346
- * @internal
347
- */
348
- const parseLatex = (value) => {
349
- const parsed = unifiedLatexUtilParse.parseMath(value);
350
- const paragraphs = [[]];
351
- let runs = paragraphs[0];
352
- for (const n of parsed) {
353
- const res = mapNode(n, runs);
354
- if (!res) {
355
- // line break
356
- paragraphs.push((runs = []));
357
- }
358
- else {
359
- runs.push(...res);
360
- }
361
- }
362
- return paragraphs;
363
- };
364
-
365
- const ORDERED_LIST_REF = "ordered";
366
- const INDENT = 0.5;
367
- const DEFAULT_NUMBERINGS = [
368
- {
369
- level: 0,
370
- format: docx.LevelFormat.DECIMAL,
371
- text: "%1.",
372
- alignment: docx.AlignmentType.START,
373
- },
374
- {
375
- level: 1,
376
- format: docx.LevelFormat.DECIMAL,
377
- text: "%2.",
378
- alignment: docx.AlignmentType.START,
379
- style: {
380
- paragraph: {
381
- indent: { start: docx.convertInchesToTwip(INDENT * 1) },
382
- },
383
- },
384
- },
385
- {
386
- level: 2,
387
- format: docx.LevelFormat.DECIMAL,
388
- text: "%3.",
389
- alignment: docx.AlignmentType.START,
390
- style: {
391
- paragraph: {
392
- indent: { start: docx.convertInchesToTwip(INDENT * 2) },
393
- },
394
- },
395
- },
396
- {
397
- level: 3,
398
- format: docx.LevelFormat.DECIMAL,
399
- text: "%4.",
400
- alignment: docx.AlignmentType.START,
401
- style: {
402
- paragraph: {
403
- indent: { start: docx.convertInchesToTwip(INDENT * 3) },
404
- },
405
- },
406
- },
407
- {
408
- level: 4,
409
- format: docx.LevelFormat.DECIMAL,
410
- text: "%5.",
411
- alignment: docx.AlignmentType.START,
412
- style: {
413
- paragraph: {
414
- indent: { start: docx.convertInchesToTwip(INDENT * 4) },
415
- },
416
- },
417
- },
418
- {
419
- level: 5,
420
- format: docx.LevelFormat.DECIMAL,
421
- text: "%6.",
422
- alignment: docx.AlignmentType.START,
423
- style: {
424
- paragraph: {
425
- indent: { start: docx.convertInchesToTwip(INDENT * 5) },
426
- },
427
- },
428
- },
429
- ];
430
- const createFootnoteRegistry = () => {
431
- const idToInternalId = new Map();
432
- const defs = new Map();
433
- const getId = (id) => {
434
- let internalId = idToInternalId.get(id);
435
- if (internalId == null) {
436
- idToInternalId.set(id, (internalId = idToInternalId.size + 1));
437
- }
438
- return internalId;
439
- };
440
- return {
441
- ref: (id) => {
442
- return getId(id);
443
- },
444
- def: (id, def) => {
445
- const internalId = getId(id);
446
- defs.set(internalId, def);
447
- },
448
- footnotes: () => {
449
- return defs.entries().reduce((acc, [key, def]) => {
450
- acc[key] = def;
451
- return acc;
452
- }, {});
453
- },
454
- };
455
- };
456
- const mdastToDocx = async (node, { output = "buffer", title, subject, creator, keywords, description, lastModifiedBy, revision, styles, background, }, images) => {
124
+ const mdastToDocx = async (node, { output = "buffer", title, subject, creator, keywords, description, lastModifiedBy, revision, styles, background, }, images, latex) => {
457
125
  const definition = {};
458
- unistUtilVisit.visit(node, "definition", (node) => {
126
+ visit(node, "definition", (node) => {
459
127
  definition[node.identifier] = node.url;
460
128
  });
461
129
  const footnote = createFootnoteRegistry();
130
+ const numbering = createNumberingRegistry();
462
131
  const nodes = convertNodes(node.children, {
463
132
  deco: {},
464
133
  images,
465
134
  indent: 0,
466
135
  def: definition,
467
136
  footnote,
137
+ numbering,
138
+ latex,
468
139
  });
469
- const doc = new docx.Document({
140
+ const doc = new Document({
470
141
  title,
471
142
  subject,
472
143
  creator,
@@ -479,23 +150,16 @@ const mdastToDocx = async (node, { output = "buffer", title, subject, creator, k
479
150
  footnotes: footnote.footnotes(),
480
151
  sections: [{ children: nodes }],
481
152
  numbering: {
482
- config: [
483
- {
484
- reference: ORDERED_LIST_REF,
485
- levels: DEFAULT_NUMBERINGS,
486
- },
487
- ],
153
+ config: numbering.getAll(),
488
154
  },
489
155
  });
490
156
  switch (output) {
491
157
  case "buffer":
492
- const bufOut = await docx.Packer.toBuffer(doc);
493
- // feature detection instead of environment detection, but if Buffer exists
494
- // it's probably Node. If not, return the Uint8Array that JSZip returns
495
- // when it doesn't detect a Node environment.
496
- return typeof Buffer === "function" ? Buffer.from(bufOut) : bufOut;
158
+ return Packer.toBuffer(doc);
159
+ case "arrayBuffer":
160
+ return Packer.toArrayBuffer(doc);
497
161
  case "blob":
498
- return docx.Packer.toBlob(doc);
162
+ return Packer.toBlob(doc);
499
163
  }
500
164
  };
501
165
  const convertNodes = (nodes, ctx) => {
@@ -587,255 +251,605 @@ const convertNodes = (nodes, ctx) => {
587
251
  }
588
252
  break;
589
253
  }
590
- case "footnote": {
591
- // inline footnote was removed in mdast v5
592
- break;
254
+ case "footnote": {
255
+ // inline footnote was removed in mdast v5
256
+ break;
257
+ }
258
+ case "footnoteReference":
259
+ results.push(buildFootnoteReference(node, ctx));
260
+ break;
261
+ case "math":
262
+ results.push(...buildMath(node, ctx));
263
+ break;
264
+ case "inlineMath":
265
+ results.push(buildInlineMath(node, ctx));
266
+ break;
267
+ default:
268
+ unreachable();
269
+ break;
270
+ }
271
+ }
272
+ return results;
273
+ };
274
+ const buildParagraph = ({ children }, ctx) => {
275
+ const list = ctx.list;
276
+ const nodes = convertNodes(children, ctx);
277
+ if (list && list.checked != null) {
278
+ nodes.unshift(new CheckBox({
279
+ checked: list.checked,
280
+ checkedState: { value: "2611" },
281
+ uncheckedState: { value: "2610" },
282
+ }));
283
+ }
284
+ return new Paragraph({
285
+ children: nodes,
286
+ indent: ctx.indent > 0
287
+ ? {
288
+ start: convertInchesToTwip(INDENT * ctx.indent),
289
+ }
290
+ : undefined,
291
+ ...(list &&
292
+ (list.ordered
293
+ ? {
294
+ numbering: {
295
+ reference: list.reference,
296
+ level: list.level,
297
+ },
298
+ }
299
+ : {
300
+ bullet: {
301
+ level: list.level,
302
+ },
303
+ })),
304
+ });
305
+ };
306
+ const buildHeading = ({ children, depth }, ctx) => {
307
+ let headingLevel;
308
+ switch (depth) {
309
+ case 1:
310
+ headingLevel = HeadingLevel.TITLE;
311
+ break;
312
+ case 2:
313
+ headingLevel = HeadingLevel.HEADING_1;
314
+ break;
315
+ case 3:
316
+ headingLevel = HeadingLevel.HEADING_2;
317
+ break;
318
+ case 4:
319
+ headingLevel = HeadingLevel.HEADING_3;
320
+ break;
321
+ case 5:
322
+ headingLevel = HeadingLevel.HEADING_4;
323
+ break;
324
+ case 6:
325
+ headingLevel = HeadingLevel.HEADING_5;
326
+ break;
327
+ }
328
+ const nodes = convertNodes(children, ctx);
329
+ return new Paragraph({
330
+ heading: headingLevel,
331
+ children: nodes,
332
+ });
333
+ };
334
+ const buildThematicBreak = (_) => {
335
+ return new Paragraph({
336
+ thematicBreak: true,
337
+ });
338
+ };
339
+ const buildBlockquote = ({ children }, ctx) => {
340
+ return convertNodes(children, {
341
+ ...ctx,
342
+ indent: ctx.indent + 1,
343
+ });
344
+ };
345
+ const buildList = ({ children, ordered, start: _start, spread: _spread }, ctx) => {
346
+ var _a;
347
+ const isTopLevel = !ctx.list;
348
+ const list = {
349
+ level: ctx.list ? ctx.list.level + 1 : 0,
350
+ ordered: !!ordered,
351
+ reference: isTopLevel && ordered
352
+ ? ctx.numbering.create()
353
+ : ((_a = ctx.list) === null || _a === void 0 ? void 0 : _a.reference) || ORDERED_LIST_REF,
354
+ };
355
+ return children.flatMap((item) => {
356
+ return buildListItem(item, {
357
+ ...ctx,
358
+ list,
359
+ });
360
+ });
361
+ };
362
+ const buildListItem = ({ children, checked, spread: _spread }, ctx) => {
363
+ return convertNodes(children, {
364
+ ...ctx,
365
+ ...(ctx.list && { list: { ...ctx.list, checked: checked !== null && checked !== void 0 ? checked : undefined } }),
366
+ });
367
+ };
368
+ const buildTable = ({ children, align }, ctx) => {
369
+ const cellAligns = align === null || align === void 0 ? void 0 : align.map((a) => {
370
+ switch (a) {
371
+ case "left":
372
+ return AlignmentType.LEFT;
373
+ case "right":
374
+ return AlignmentType.RIGHT;
375
+ case "center":
376
+ return AlignmentType.CENTER;
377
+ default:
378
+ return AlignmentType.LEFT;
379
+ }
380
+ });
381
+ return new Table({
382
+ rows: children.map((r) => {
383
+ return buildTableRow(r, ctx, cellAligns);
384
+ }),
385
+ });
386
+ };
387
+ const buildTableRow = ({ children }, ctx, cellAligns) => {
388
+ return new TableRow({
389
+ children: children.map((c, i) => {
390
+ return buildTableCell(c, ctx, cellAligns === null || cellAligns === void 0 ? void 0 : cellAligns[i]);
391
+ }),
392
+ });
393
+ };
394
+ const buildTableCell = ({ children }, ctx, align) => {
395
+ const nodes = convertNodes(children, ctx);
396
+ return new TableCell({
397
+ children: [
398
+ new Paragraph({
399
+ alignment: align,
400
+ children: nodes,
401
+ }),
402
+ ],
403
+ });
404
+ };
405
+ const buildHtml = ({ value }) => {
406
+ // FIXME: transform to text for now
407
+ return new Paragraph({
408
+ children: [buildText(value, {})],
409
+ });
410
+ };
411
+ const buildCode = ({ value, lang: _lang, meta: _meta, }) => {
412
+ // FIXME: transform to text for now
413
+ return new Paragraph({
414
+ children: [buildText(value, {})],
415
+ });
416
+ };
417
+ const buildMath = ({ value }, ctx) => {
418
+ return ctx.latex(value).map((runs) => new Paragraph({
419
+ children: [
420
+ new Math({
421
+ children: runs,
422
+ }),
423
+ ],
424
+ }));
425
+ };
426
+ const buildInlineMath = ({ value }, ctx) => {
427
+ return new Math({
428
+ children: ctx.latex(value).flatMap((runs) => runs),
429
+ });
430
+ };
431
+ const buildText = (text, deco) => {
432
+ return new TextRun({
433
+ text,
434
+ bold: deco.strong,
435
+ italics: deco.emphasis,
436
+ strike: deco.delete,
437
+ });
438
+ };
439
+ const buildBreak = (_) => {
440
+ return new TextRun({ text: "", break: 1 });
441
+ };
442
+ const buildLink = ({ children, url }, ctx) => {
443
+ const nodes = convertNodes(children, ctx);
444
+ return new ExternalHyperlink({
445
+ link: url,
446
+ children: nodes,
447
+ });
448
+ };
449
+ const buildImage = ({ url }, images) => {
450
+ const img = images[url];
451
+ invariant(img, `Fetch image was failed: ${url}`);
452
+ const { image, width, height } = img;
453
+ return new ImageRun({
454
+ type: img.type,
455
+ data: image,
456
+ transformation: {
457
+ width,
458
+ height,
459
+ },
460
+ });
461
+ };
462
+ const buildLinkReference = ({ children, identifier }, ctx) => {
463
+ const def = ctx.def[identifier];
464
+ if (def == null) {
465
+ return convertNodes(children, ctx);
466
+ }
467
+ return [buildLink({ children, url: def }, ctx)];
468
+ };
469
+ const buildImageReference = ({ identifier }, ctx) => {
470
+ const def = ctx.def[identifier];
471
+ if (def == null) {
472
+ return;
473
+ }
474
+ return buildImage({ url: def }, ctx.images);
475
+ };
476
+ const registerFootnoteDefinition = ({ children, identifier }, ctx) => {
477
+ const definition = {
478
+ children: children.map((node) => {
479
+ // Convert each node and extract the first result as a paragraph
480
+ const nodes = convertNodes([node], ctx);
481
+ if (nodes[0] instanceof Paragraph) {
482
+ return nodes[0];
483
+ }
484
+ // For non-paragraph content, wrap in a paragraph
485
+ return new Paragraph({ children: nodes });
486
+ }),
487
+ };
488
+ ctx.footnote.def(identifier, definition);
489
+ };
490
+ const buildFootnoteReference = ({ identifier }, ctx) => {
491
+ return new FootnoteReferenceRun(ctx.footnote.ref(identifier));
492
+ };
493
+
494
+ const hasSquareBrackets = (arg) => {
495
+ return !!arg && arg.openMark === "[" && arg.closeMark === "]";
496
+ };
497
+ const hasCurlyBrackets = (arg) => {
498
+ return !!arg && arg.openMark === "{" && arg.closeMark === "}";
499
+ };
500
+ const mapString = (s) => new MathRun(s);
501
+ const mapMacro = (n, runs) => {
502
+ var _a, _b, _c, _d, _e, _f, _g, _h;
503
+ switch (n.content) {
504
+ case "#":
505
+ return mapString("#");
506
+ case "$":
507
+ return mapString("$");
508
+ case "%":
509
+ return mapString("%");
510
+ case "&":
511
+ return mapString("&");
512
+ case "textasciitilde":
513
+ return mapString("~");
514
+ case "textasciicircum":
515
+ return mapString("^");
516
+ case "textbackslash":
517
+ return mapString("∖");
518
+ case "{":
519
+ return mapString("{");
520
+ case "}":
521
+ return mapString("}");
522
+ case "textbar":
523
+ return mapString("|");
524
+ case "textless":
525
+ return mapString("<");
526
+ case "textgreater":
527
+ return mapString(">");
528
+ case "neq":
529
+ return mapString("≠");
530
+ case "sim":
531
+ return mapString("∼");
532
+ case "simeq":
533
+ return mapString("≃");
534
+ case "approx":
535
+ return mapString("≈");
536
+ case "fallingdotseq":
537
+ return mapString("≒");
538
+ case "risingdotseq":
539
+ return mapString("≓");
540
+ case "equiv":
541
+ return mapString("≡");
542
+ case "geq":
543
+ return mapString("≥");
544
+ case "geqq":
545
+ return mapString("≧");
546
+ case "leq":
547
+ return mapString("≤");
548
+ case "leqq":
549
+ return mapString("≦");
550
+ case "gg":
551
+ return mapString("≫");
552
+ case "ll":
553
+ return mapString("≪");
554
+ case "times":
555
+ return mapString("×");
556
+ case "div":
557
+ return mapString("÷");
558
+ case "pm":
559
+ return mapString("±");
560
+ case "mp":
561
+ return mapString("∓");
562
+ case "oplus":
563
+ return mapString("⊕");
564
+ case "ominus":
565
+ return mapString("⊖");
566
+ case "otimes":
567
+ return mapString("⊗");
568
+ case "oslash":
569
+ return mapString("⊘");
570
+ case "circ":
571
+ return mapString("∘");
572
+ case "cdot":
573
+ return mapString("⋅");
574
+ case "bullet":
575
+ return mapString("∙");
576
+ case "ltimes":
577
+ return mapString("⋉");
578
+ case "rtimes":
579
+ return mapString("⋊");
580
+ case "in":
581
+ return mapString("∈");
582
+ case "ni":
583
+ return mapString("∋");
584
+ case "notin":
585
+ return mapString("∉");
586
+ case "subset":
587
+ return mapString("⊂");
588
+ case "supset":
589
+ return mapString("⊃");
590
+ case "subseteq":
591
+ return mapString("⊆");
592
+ case "supseteq":
593
+ return mapString("⊇");
594
+ case "nsubseteq":
595
+ return mapString("⊈");
596
+ case "nsupseteq":
597
+ return mapString("⊉");
598
+ case "subsetneq":
599
+ return mapString("⊊");
600
+ case "supsetneq":
601
+ return mapString("⊋");
602
+ case "cap":
603
+ return mapString("∩");
604
+ case "cup":
605
+ return mapString("∪");
606
+ case "emptyset":
607
+ return mapString("∅");
608
+ case "infty":
609
+ return mapString("∞");
610
+ case "partial":
611
+ return mapString("∂");
612
+ case "aleph":
613
+ return mapString("ℵ");
614
+ case "hbar":
615
+ return mapString("ℏ");
616
+ case "wp":
617
+ return mapString("℘");
618
+ case "Re":
619
+ return mapString("ℜ");
620
+ case "Im":
621
+ return mapString("ℑ");
622
+ case "alpha":
623
+ return mapString("α");
624
+ case "beta":
625
+ return mapString("β");
626
+ case "gamma":
627
+ return mapString("γ");
628
+ case "delta":
629
+ return mapString("δ");
630
+ case "epsilon":
631
+ return mapString("ϵ");
632
+ case "zeta":
633
+ return mapString("ζ");
634
+ case "eta":
635
+ return mapString("η");
636
+ case "theta":
637
+ return mapString("θ");
638
+ case "iota":
639
+ return mapString("ι");
640
+ case "kappa":
641
+ return mapString("κ");
642
+ case "lambda":
643
+ return mapString("λ");
644
+ case "eta":
645
+ return mapString("η");
646
+ case "mu":
647
+ return mapString("μ");
648
+ case "nu":
649
+ return mapString("ν");
650
+ case "xi":
651
+ return mapString("ξ");
652
+ case "pi":
653
+ return mapString("π");
654
+ case "rho":
655
+ return mapString("ρ");
656
+ case "sigma":
657
+ return mapString("σ");
658
+ case "tau":
659
+ return mapString("τ");
660
+ case "upsilon":
661
+ return mapString("υ");
662
+ case "phi":
663
+ return mapString("ϕ");
664
+ case "chi":
665
+ return mapString("χ");
666
+ case "psi":
667
+ return mapString("ψ");
668
+ case "omega":
669
+ return mapString("ω");
670
+ case "varepsilon":
671
+ return mapString("ε");
672
+ case "vartheta":
673
+ return mapString("ϑ");
674
+ case "varrho":
675
+ return mapString("ϱ");
676
+ case "varsigma":
677
+ return mapString("ς");
678
+ case "varphi":
679
+ return mapString("φ");
680
+ case "Gamma":
681
+ return mapString("Γ");
682
+ case "Delta":
683
+ return mapString("Δ");
684
+ case "Theta":
685
+ return mapString("Θ");
686
+ case "Lambda":
687
+ return mapString("Λ");
688
+ case "Xi":
689
+ return mapString("Ξ");
690
+ case "Pi":
691
+ return mapString("Π");
692
+ case "Sigma":
693
+ return mapString("Σ");
694
+ case "Upsilon":
695
+ return mapString("Υ");
696
+ case "Phi":
697
+ return mapString("Φ");
698
+ case "Psi":
699
+ return mapString("Ψ");
700
+ case "Omega":
701
+ return mapString("Ω");
702
+ case "newline":
703
+ case "\\":
704
+ // line break
705
+ return false;
706
+ case "^": {
707
+ const prev = runs.pop();
708
+ if (!prev)
709
+ break;
710
+ return new MathSuperScript({
711
+ children: [prev],
712
+ superScript: mapGroup((_c = (_b = (_a = n.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) !== null && _c !== void 0 ? _c : []),
713
+ });
714
+ }
715
+ case "_": {
716
+ const prev = runs.pop();
717
+ if (!prev)
718
+ break;
719
+ return new MathSubScript({
720
+ children: [prev],
721
+ subScript: mapGroup((_f = (_e = (_d = n.args) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.content) !== null && _f !== void 0 ? _f : []),
722
+ });
723
+ }
724
+ case "hat":
725
+ // TODO: implement
726
+ break;
727
+ case "widehat":
728
+ // TODO: implement
729
+ break;
730
+ case "sum": {
731
+ // TODO: support superscript and subscript
732
+ return new MathSum({
733
+ children: [],
734
+ });
735
+ }
736
+ case "int":
737
+ return mapString("∫");
738
+ case "frac":
739
+ case "tfrac":
740
+ case "dfrac": {
741
+ const args = (_g = n.args) !== null && _g !== void 0 ? _g : [];
742
+ if (args.length === 2 &&
743
+ hasCurlyBrackets(args[0]) &&
744
+ hasCurlyBrackets(args[1])) {
745
+ return new MathFraction({
746
+ numerator: mapGroup(args[0].content),
747
+ denominator: mapGroup(args[1].content),
748
+ });
749
+ }
750
+ break;
751
+ }
752
+ case "sqrt": {
753
+ const args = (_h = n.args) !== null && _h !== void 0 ? _h : [];
754
+ if (args.length === 1 && hasCurlyBrackets(args[0])) {
755
+ return new MathRadical({
756
+ children: mapGroup(args[0].content),
757
+ });
593
758
  }
594
- case "footnoteReference":
595
- results.push(buildFootnoteReference(node, ctx));
596
- break;
597
- case "math":
598
- results.push(...buildMath(node));
599
- break;
600
- case "inlineMath":
601
- results.push(buildInlineMath(node));
602
- break;
603
- default:
604
- unreachable();
605
- break;
759
+ if (args.length === 2 &&
760
+ hasSquareBrackets(args[0]) &&
761
+ hasCurlyBrackets(args[1])) {
762
+ return new MathRadical({
763
+ children: mapGroup(args[1].content),
764
+ degree: mapGroup(args[0].content),
765
+ });
766
+ }
767
+ break;
606
768
  }
607
769
  }
608
- return results;
770
+ return mapString(n.content);
609
771
  };
610
- const buildParagraph = ({ children }, ctx) => {
611
- const list = ctx.list;
612
- const nodes = convertNodes(children, ctx);
613
- if (list && list.checked != null) {
614
- nodes.unshift(new docx.CheckBox({
615
- checked: list.checked,
616
- checkedState: { value: "2611" },
617
- uncheckedState: { value: "2610" },
618
- }));
772
+ const mapGroup = (nodes) => {
773
+ const group = [];
774
+ for (const c of nodes) {
775
+ group.push(...(mapNode(c, group) || []));
619
776
  }
620
- return new docx.Paragraph({
621
- children: nodes,
622
- indent: ctx.indent > 0
623
- ? {
624
- start: docx.convertInchesToTwip(INDENT * ctx.indent),
625
- }
626
- : undefined,
627
- ...(list &&
628
- (list.ordered
629
- ? {
630
- numbering: {
631
- reference: ORDERED_LIST_REF,
632
- level: list.level,
633
- },
634
- }
635
- : {
636
- bullet: {
637
- level: list.level,
638
- },
639
- })),
640
- });
777
+ return group;
641
778
  };
642
- const buildHeading = ({ children, depth }, ctx) => {
643
- let headingLevel;
644
- switch (depth) {
645
- case 1:
646
- headingLevel = docx.HeadingLevel.TITLE;
779
+ const mapNode = (n, runs) => {
780
+ switch (n.type) {
781
+ case "root":
647
782
  break;
648
- case 2:
649
- headingLevel = docx.HeadingLevel.HEADING_1;
783
+ case "string":
784
+ return [mapString(n.content)];
785
+ case "whitespace":
650
786
  break;
651
- case 3:
652
- headingLevel = docx.HeadingLevel.HEADING_2;
787
+ case "parbreak":
653
788
  break;
654
- case 4:
655
- headingLevel = docx.HeadingLevel.HEADING_3;
789
+ case "comment":
656
790
  break;
657
- case 5:
658
- headingLevel = docx.HeadingLevel.HEADING_4;
791
+ case "macro":
792
+ const run = mapMacro(n, runs);
793
+ if (!run) {
794
+ // line break
795
+ return false;
796
+ }
797
+ else {
798
+ return [run];
799
+ }
800
+ case "environment":
801
+ case "mathenv":
659
802
  break;
660
- case 6:
661
- headingLevel = docx.HeadingLevel.HEADING_5;
803
+ case "verbatim":
804
+ break;
805
+ case "inlinemath":
806
+ break;
807
+ case "displaymath":
662
808
  break;
809
+ case "group":
810
+ return mapGroup(n.content);
811
+ case "verb":
812
+ break;
813
+ default:
814
+ unreachable();
663
815
  }
664
- const nodes = convertNodes(children, ctx);
665
- return new docx.Paragraph({
666
- heading: headingLevel,
667
- children: nodes,
668
- });
669
- };
670
- const buildThematicBreak = (_) => {
671
- return new docx.Paragraph({
672
- thematicBreak: true,
673
- });
674
- };
675
- const buildBlockquote = ({ children }, ctx) => {
676
- return convertNodes(children, {
677
- ...ctx,
678
- indent: ctx.indent + 1,
679
- });
680
- };
681
- const buildList = ({ children, ordered, start: _start, spread: _spread }, ctx) => {
682
- const list = {
683
- level: ctx.list ? ctx.list.level + 1 : 0,
684
- ordered: !!ordered,
685
- };
686
- return children.flatMap((item) => {
687
- return buildListItem(item, {
688
- ...ctx,
689
- list,
690
- });
691
- });
692
- };
693
- const buildListItem = ({ children, checked, spread: _spread }, ctx) => {
694
- return convertNodes(children, {
695
- ...ctx,
696
- ...(ctx.list && { list: { ...ctx.list, checked: checked !== null && checked !== void 0 ? checked : undefined } }),
697
- });
816
+ return [];
698
817
  };
699
- const buildTable = ({ children, align }, ctx) => {
700
- const cellAligns = align === null || align === void 0 ? void 0 : align.map((a) => {
701
- switch (a) {
702
- case "left":
703
- return docx.AlignmentType.LEFT;
704
- case "right":
705
- return docx.AlignmentType.RIGHT;
706
- case "center":
707
- return docx.AlignmentType.CENTER;
708
- default:
709
- return docx.AlignmentType.LEFT;
818
+ /**
819
+ * @internal
820
+ */
821
+ const parseLatex = (value) => {
822
+ const parsed = parseMath(value);
823
+ const paragraphs = [[]];
824
+ let runs = paragraphs[0];
825
+ for (const n of parsed) {
826
+ const res = mapNode(n, runs);
827
+ if (!res) {
828
+ // line break
829
+ paragraphs.push((runs = []));
830
+ }
831
+ else {
832
+ runs.push(...res);
710
833
  }
711
- });
712
- return new docx.Table({
713
- rows: children.map((r) => {
714
- return buildTableRow(r, ctx, cellAligns);
715
- }),
716
- });
717
- };
718
- const buildTableRow = ({ children }, ctx, cellAligns) => {
719
- return new docx.TableRow({
720
- children: children.map((c, i) => {
721
- return buildTableCell(c, ctx, cellAligns === null || cellAligns === void 0 ? void 0 : cellAligns[i]);
722
- }),
723
- });
724
- };
725
- const buildTableCell = ({ children }, ctx, align) => {
726
- const nodes = convertNodes(children, ctx);
727
- return new docx.TableCell({
728
- children: [
729
- new docx.Paragraph({
730
- alignment: align,
731
- children: nodes,
732
- }),
733
- ],
734
- });
735
- };
736
- const buildHtml = ({ value }) => {
737
- // FIXME: transform to text for now
738
- return new docx.Paragraph({
739
- children: [buildText(value, {})],
740
- });
741
- };
742
- const buildCode = ({ value, lang: _lang, meta: _meta, }) => {
743
- // FIXME: transform to text for now
744
- return new docx.Paragraph({
745
- children: [buildText(value, {})],
746
- });
747
- };
748
- const buildMath = ({ value }) => {
749
- return parseLatex(value).map((runs) => new docx.Paragraph({
750
- children: [
751
- new docx.Math({
752
- children: runs,
753
- }),
754
- ],
755
- }));
756
- };
757
- const buildInlineMath = ({ value }) => {
758
- return new docx.Math({
759
- children: parseLatex(value).flatMap((runs) => runs),
760
- });
761
- };
762
- const buildText = (text, deco) => {
763
- return new docx.TextRun({
764
- text,
765
- bold: deco.strong,
766
- italics: deco.emphasis,
767
- strike: deco.delete,
768
- });
769
- };
770
- const buildBreak = (_) => {
771
- return new docx.TextRun({ text: "", break: 1 });
772
- };
773
- const buildLink = ({ children, url }, ctx) => {
774
- const nodes = convertNodes(children, ctx);
775
- return new docx.ExternalHyperlink({
776
- link: url,
777
- children: nodes,
778
- });
779
- };
780
- const buildImage = ({ url }, images) => {
781
- const img = images[url];
782
- invariant(img, `Fetch image was failed: ${url}`);
783
- const { image, width, height } = img;
784
- return new docx.ImageRun({
785
- data: image,
786
- transformation: {
787
- width,
788
- height,
789
- },
790
- });
791
- };
792
- const buildLinkReference = ({ children, identifier }, ctx) => {
793
- const def = ctx.def[identifier];
794
- if (def == null) {
795
- return convertNodes(children, ctx);
796
- }
797
- return [buildLink({ children, url: def }, ctx)];
798
- };
799
- const buildImageReference = ({ identifier }, ctx) => {
800
- const def = ctx.def[identifier];
801
- if (def == null) {
802
- return;
803
834
  }
804
- return buildImage({ url: def }, ctx.images);
805
- };
806
- const registerFootnoteDefinition = ({ children, identifier }, ctx) => {
807
- const definition = {
808
- children: children.map((node) => {
809
- // Convert each node and extract the first result as a paragraph
810
- const nodes = convertNodes([node], ctx);
811
- if (nodes[0] instanceof docx.Paragraph) {
812
- return nodes[0];
813
- }
814
- // For non-paragraph content, wrap in a paragraph
815
- return new docx.Paragraph({ children: nodes });
816
- }),
817
- };
818
- ctx.footnote.def(identifier, definition);
819
- };
820
- const buildFootnoteReference = ({ identifier }, ctx) => {
821
- return new docx.FootnoteReferenceRun(ctx.footnote.ref(identifier));
835
+ return paragraphs;
822
836
  };
823
837
 
824
838
  const plugin = function (opts = {}) {
825
839
  let images = {};
826
840
  this.Compiler = (node) => {
827
- return mdastToDocx(node, opts, images);
841
+ return mdastToDocx(node, opts, images, parseLatex);
828
842
  };
829
843
  return async (node) => {
830
844
  const imageList = [];
831
- unistUtilVisit.visit(node, "image", (node) => {
845
+ visit(node, "image", (node) => {
832
846
  imageList.push(node);
833
847
  });
834
848
  const defs = new Map();
835
- unistUtilVisit.visit(node, "definition", (node) => {
849
+ visit(node, "definition", (node) => {
836
850
  defs.set(node.identifier, node);
837
851
  });
838
- unistUtilVisit.visit(node, "imageReference", (node) => {
852
+ visit(node, "imageReference", (node) => {
839
853
  const maybeImage = defs.get(node.identifier);
840
854
  if (maybeImage) {
841
855
  imageList.push(maybeImage);
@@ -865,5 +879,5 @@ const plugin = function (opts = {}) {
865
879
  };
866
880
  };
867
881
 
868
- module.exports = plugin;
882
+ export { plugin as default };
869
883
  //# sourceMappingURL=index.js.map