tex2typst 0.0.17 → 0.0.19

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/writer.js DELETED
@@ -1,356 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TypstWriter = exports.TypstWriterError = void 0;
4
- const map_1 = require("./map");
5
- // symbols that are supported by Typst but not by KaTeX
6
- const TYPST_INTRINSIC_SYMBOLS = [
7
- 'dim',
8
- 'id',
9
- 'im',
10
- 'mod',
11
- 'Pr',
12
- 'sech',
13
- 'csch',
14
- // 'sgn
15
- ];
16
- class TypstWriterError extends Error {
17
- constructor(message, node) {
18
- super(message);
19
- this.name = "TypstWriterError";
20
- this.node = node;
21
- }
22
- }
23
- exports.TypstWriterError = TypstWriterError;
24
- class TypstWriter {
25
- constructor(nonStrict, preferTypstIntrinsic) {
26
- this.buffer = "";
27
- this.queue = [];
28
- this.needSpaceAfterSingleItemScript = false;
29
- this.insideFunctionDepth = 0;
30
- this.nonStrict = nonStrict;
31
- this.preferTypstIntrinsic = preferTypstIntrinsic;
32
- }
33
- writeBuffer(str) {
34
- if (this.needSpaceAfterSingleItemScript && /^[0-9a-zA-Z\(]/.test(str)) {
35
- this.buffer += ' ';
36
- }
37
- else {
38
- let no_need_space = false;
39
- // starting clause
40
- no_need_space || (no_need_space = /[\(\|]$/.test(this.buffer) && /^\w/.test(str));
41
- // putting punctuation
42
- no_need_space || (no_need_space = /^[}()_^,;!\|]$/.test(str));
43
- // putting a prime
44
- no_need_space || (no_need_space = str === "'");
45
- // continue a number
46
- no_need_space || (no_need_space = /[0-9]$/.test(this.buffer) && /^[0-9]/.test(str));
47
- // leading sign
48
- no_need_space || (no_need_space = /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+");
49
- // buffer is empty
50
- no_need_space || (no_need_space = this.buffer === "");
51
- // other cases
52
- no_need_space || (no_need_space = /[\s"_^{\(]$/.test(this.buffer));
53
- if (!no_need_space) {
54
- this.buffer += ' ';
55
- }
56
- }
57
- if (this.needSpaceAfterSingleItemScript) {
58
- this.needSpaceAfterSingleItemScript = false;
59
- }
60
- this.buffer += str;
61
- }
62
- append(node) {
63
- if (node.type === 'empty') {
64
- return;
65
- }
66
- else if (node.type === 'ordgroup') {
67
- // const index = this.startBlock();
68
- node.args.forEach((arg) => this.append(arg));
69
- // this.endBlock(index);
70
- }
71
- else if (node.type === 'atom') {
72
- let content = node.content;
73
- if (node.content === ',' && this.insideFunctionDepth > 0) {
74
- content = 'comma';
75
- }
76
- this.queue.push({ type: 'atom', content: content });
77
- }
78
- else if (node.type === 'symbol') {
79
- this.queue.push({ type: 'symbol', content: node.content });
80
- }
81
- else if (node.type === 'text') {
82
- this.queue.push(node);
83
- }
84
- else if (node.type === 'supsub') {
85
- let { base, sup, sub } = node.irregularData;
86
- // Special logic for overbrace
87
- if (base && base.type === 'unaryFunc' && base.content === '\\overbrace' && sup) {
88
- this.append({ type: 'binaryFunc', content: '\\overbrace', args: [base.args[0], sup] });
89
- return;
90
- }
91
- else if (base && base.type === 'unaryFunc' && base.content === '\\underbrace' && sub) {
92
- this.append({ type: 'binaryFunc', content: '\\underbrace', args: [base.args[0], sub] });
93
- return;
94
- }
95
- if (!base) {
96
- this.queue.push({ type: 'text', content: '' });
97
- }
98
- else {
99
- this.appendWithBracketsIfNeeded(base);
100
- }
101
- let trailing_space_needed = false;
102
- const has_prime = (sup && sup.type === 'symbol' && sup.content === '\\prime');
103
- if (has_prime) {
104
- // Put prime symbol before '_'. Because $y_1'$ is not displayed properly in Typst (so far)
105
- // e.g.
106
- // y_1' -> y'_1
107
- // y_{a_1}' -> y'_{a_1}
108
- this.queue.push({ type: 'atom', content: '\'' });
109
- trailing_space_needed = false;
110
- }
111
- if (sub) {
112
- this.queue.push({ type: 'atom', content: '_' });
113
- trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
114
- }
115
- if (sup && !has_prime) {
116
- this.queue.push({ type: 'atom', content: '^' });
117
- trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
118
- }
119
- if (trailing_space_needed) {
120
- this.queue.push({ type: 'softSpace', content: '' });
121
- }
122
- }
123
- else if (node.type === 'leftright') {
124
- const [left, body, right] = node.args;
125
- // These pairs will be handled by Typst compiler by default. No need to add lr()
126
- if (["[]", "()", "{}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
127
- this.append(left);
128
- this.append(body);
129
- this.append(right);
130
- return;
131
- }
132
- const func_symbol = { type: 'symbol', content: 'lr' };
133
- this.queue.push(func_symbol);
134
- this.insideFunctionDepth++;
135
- this.queue.push({ type: 'atom', content: '(' });
136
- this.append(left);
137
- this.append(body);
138
- this.append(right);
139
- this.queue.push({ type: 'atom', content: ')' });
140
- this.insideFunctionDepth--;
141
- }
142
- else if (node.type === 'binaryFunc') {
143
- const func_symbol = { type: 'symbol', content: node.content };
144
- const [arg0, arg1] = node.args;
145
- this.queue.push(func_symbol);
146
- this.insideFunctionDepth++;
147
- this.queue.push({ type: 'atom', content: '(' });
148
- this.append(arg0);
149
- this.queue.push({ type: 'atom', content: ',' });
150
- this.append(arg1);
151
- this.queue.push({ type: 'atom', content: ')' });
152
- this.insideFunctionDepth--;
153
- }
154
- else if (node.type === 'unaryFunc') {
155
- const func_symbol = { type: 'symbol', content: node.content };
156
- const arg0 = node.args[0];
157
- if (node.content === '\\sqrt' && node.irregularData) {
158
- func_symbol.content = 'root';
159
- this.queue.push(func_symbol);
160
- this.insideFunctionDepth++;
161
- this.queue.push({ type: 'atom', content: '(' });
162
- this.append(node.irregularData); // the number of times to take the root
163
- this.queue.push({ type: 'atom', content: ',' });
164
- this.append(arg0);
165
- this.queue.push({ type: 'atom', content: ')' });
166
- this.insideFunctionDepth--;
167
- return;
168
- }
169
- else if (node.content === '\\mathbb') {
170
- const body = node.args[0];
171
- if (body.type === 'symbol' && /^[A-Z]$/.test(body.content)) {
172
- // \mathbb{R} -> RR
173
- this.queue.push({ type: 'symbol', content: body.content + body.content });
174
- return;
175
- }
176
- // Fall through
177
- }
178
- else if (node.content === '\\operatorname') {
179
- let body = node.args;
180
- if (body.length === 1 && body[0].type == 'ordgroup') {
181
- body = body[0].args;
182
- }
183
- const text = body.reduce((buff, n) => {
184
- // Hope convertToken() will not throw an error
185
- // If it does, the input is bad.
186
- buff += convertToken(n.content);
187
- return buff;
188
- }, "");
189
- if (this.preferTypstIntrinsic && TYPST_INTRINSIC_SYMBOLS.includes(text)) {
190
- // e.g. we prefer just sech over op("sech")
191
- this.queue.push({ type: 'symbol', content: text });
192
- }
193
- else if (text.startsWith('SyMb01-')) {
194
- // special hacks made in parseTex()
195
- this.queue.push({ type: 'symbol', content: '\\' + text.substring(7) });
196
- }
197
- else {
198
- this.queue.push({ type: 'symbol', content: 'op' });
199
- this.queue.push({ type: 'atom', content: '(' });
200
- this.queue.push({ type: 'text', content: text });
201
- this.queue.push({ type: 'atom', content: ')' });
202
- }
203
- return;
204
- }
205
- this.queue.push(func_symbol);
206
- this.insideFunctionDepth++;
207
- this.queue.push({ type: 'atom', content: '(' });
208
- this.append(arg0);
209
- this.queue.push({ type: 'atom', content: ')' });
210
- this.insideFunctionDepth--;
211
- }
212
- else if (node.type === 'align') {
213
- const matrix = node.irregularData;
214
- matrix.forEach((row, i) => {
215
- row.forEach((cell, j) => {
216
- if (j > 0) {
217
- this.queue.push({ type: 'atom', content: '&' });
218
- }
219
- this.append(cell);
220
- });
221
- if (i < matrix.length - 1) {
222
- this.queue.push({ type: 'symbol', content: '\\\\' });
223
- }
224
- });
225
- }
226
- else if (node.type === 'matrix') {
227
- const matrix = node.irregularData;
228
- this.queue.push({ type: 'symbol', content: 'mat' });
229
- this.insideFunctionDepth++;
230
- this.queue.push({ type: 'atom', content: '(' });
231
- this.queue.push({ type: 'symbol', content: 'delim: #none, ' });
232
- matrix.forEach((row, i) => {
233
- row.forEach((cell, j) => {
234
- // There is a leading & in row
235
- if (cell.type === 'ordgroup' && cell.args.length === 0) {
236
- return;
237
- }
238
- this.append(cell);
239
- // cell.args!.forEach((n) => this.append(n));
240
- if (j < row.length - 1) {
241
- this.queue.push({ type: 'atom', content: ',' });
242
- }
243
- else {
244
- if (i < matrix.length - 1) {
245
- this.queue.push({ type: 'atom', content: ';' });
246
- }
247
- }
248
- });
249
- });
250
- this.queue.push({ type: 'atom', content: ')' });
251
- this.insideFunctionDepth--;
252
- }
253
- else if (node.type === 'unknownMacro') {
254
- if (this.nonStrict) {
255
- this.queue.push({ type: 'symbol', content: node.content });
256
- }
257
- else {
258
- throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
259
- }
260
- }
261
- else {
262
- throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
263
- }
264
- }
265
- flushQueue() {
266
- this.queue.forEach((node) => {
267
- let str = "";
268
- switch (node.type) {
269
- case 'atom':
270
- str = node.content;
271
- break;
272
- case 'symbol':
273
- str = convertToken(node.content);
274
- break;
275
- case 'text':
276
- str = `"${node.content}"`;
277
- break;
278
- case 'softSpace':
279
- this.needSpaceAfterSingleItemScript = true;
280
- str = '';
281
- break;
282
- default:
283
- throw new TypstWriterError(`Unexpected node type to stringify: ${node.type}`, node);
284
- }
285
- if (str !== '') {
286
- this.writeBuffer(str);
287
- }
288
- });
289
- this.queue = [];
290
- }
291
- appendWithBracketsIfNeeded(node) {
292
- const is_single_atom = (node.type === 'atom');
293
- const is_single_function = (node.type === 'unaryFunc' || node.type === 'binaryFunc' || node.type === 'leftright');
294
- const is_single = ['atom', 'symbol', 'unaryFunc', 'binaryFunc', 'leftright'].includes(node.type);
295
- if (is_single) {
296
- this.append(node);
297
- }
298
- else {
299
- this.queue.push({
300
- type: 'atom',
301
- content: '('
302
- });
303
- this.append(node);
304
- this.queue.push({
305
- type: 'atom',
306
- content: ')'
307
- });
308
- }
309
- return is_single;
310
- }
311
- finalize() {
312
- this.flushQueue();
313
- const smartFloorPass = function (input) {
314
- // Use regex to replace all "⌊ xxx ⌋" with "floor(xxx)"
315
- let res = input.replace(/⌊\s*(.*?)\s*⌋/g, "floor($1)");
316
- // Typst disallow "floor()" with empty argument, so add am empty string inside if it's empty.
317
- res = res.replace(/floor\(\)/g, 'floor("")');
318
- return res;
319
- };
320
- const smartCeilPass = function (input) {
321
- // Use regex to replace all "⌈ xxx ⌉" with "ceil(xxx)"
322
- let res = input.replace(/⌈\s*(.*?)\s*⌉/g, "ceil($1)");
323
- // Typst disallow "ceil()" with empty argument, so add an empty string inside if it's empty.
324
- res = res.replace(/ceil\(\)/g, 'ceil("")');
325
- return res;
326
- };
327
- this.buffer = smartFloorPass(this.buffer);
328
- this.buffer = smartCeilPass(this.buffer);
329
- return this.buffer;
330
- }
331
- }
332
- exports.TypstWriter = TypstWriter;
333
- function convertToken(token) {
334
- if (/^[a-zA-Z0-9]$/.test(token)) {
335
- return token;
336
- }
337
- else if (token === '\\\\') {
338
- return '\\\n';
339
- }
340
- else if (['\\$', '\\#', '\\&', '\\_'].includes(token)) {
341
- return token;
342
- }
343
- else if (token.startsWith('\\')) {
344
- const symbol = token.slice(1);
345
- if (map_1.symbolMap.has(symbol)) {
346
- return map_1.symbolMap.get(symbol);
347
- }
348
- else {
349
- // Fall back to the original macro.
350
- // This works for \alpha, \beta, \gamma, etc.
351
- // If this.nonStrict is true, this also works for all unknown macros.
352
- return symbol;
353
- }
354
- }
355
- return token;
356
- }