tex2typst 0.1.20 → 0.2.2
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/README.md +3 -1
- package/dist/index.js +635 -313
- package/dist/parser.d.ts +21 -5
- package/dist/tex2typst.min.js +1 -1
- package/dist/types.d.ts +1 -8
- package/package.json +2 -4
- package/src/map.ts +4 -0
- package/src/parser.ts +652 -302
- package/src/types.ts +1 -9
- package/src/writer.ts +61 -59
- package/tsconfig.json +1 -1
package/src/types.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export interface KatexParseNode {
|
|
2
|
-
type: string;
|
|
3
|
-
mode: string;
|
|
4
|
-
text?: string;
|
|
5
|
-
body?: KatexParseNode | KatexParseNode[] | KatexParseNode[][];
|
|
6
|
-
loc?: any;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
1
|
export interface TexSupsubData {
|
|
10
2
|
base: TexNode;
|
|
11
3
|
sup?: TexNode;
|
|
@@ -24,7 +16,7 @@ export interface TexNode {
|
|
|
24
16
|
// For type="sqrt", it's additional argument wrapped square bracket. e.g. 3 in \sqrt[3]{x}
|
|
25
17
|
// For type="supsub", it's base, sup, and sub.
|
|
26
18
|
// For type="array", it's the 2-dimensional matrix.
|
|
27
|
-
|
|
19
|
+
data?: TexSqrtData | TexSupsubData | TexArrayData;
|
|
28
20
|
}
|
|
29
21
|
|
|
30
22
|
export interface TypstNode {
|
package/src/writer.ts
CHANGED
|
@@ -74,24 +74,24 @@ export class TypstWriter {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
public append(node: TexNode) {
|
|
77
|
-
if (node.type === 'empty') {
|
|
77
|
+
if (node.type === 'empty' || node.type === 'whitespace') {
|
|
78
78
|
return;
|
|
79
79
|
} else if (node.type === 'ordgroup') {
|
|
80
80
|
// const index = this.startBlock();
|
|
81
81
|
node.args!.forEach((arg) => this.append(arg));
|
|
82
82
|
// this.endBlock(index);
|
|
83
|
-
} else if (node.type === '
|
|
83
|
+
} else if (node.type === 'element') {
|
|
84
84
|
let content = node.content!;
|
|
85
85
|
if (node.content === ',' && this.insideFunctionDepth > 0) {
|
|
86
86
|
content = 'comma';
|
|
87
87
|
}
|
|
88
|
-
this.queue.push({ type: '
|
|
88
|
+
this.queue.push({ type: 'symbol', content: content });
|
|
89
89
|
} else if (node.type === 'symbol') {
|
|
90
90
|
this.queue.push({ type: 'symbol', content: node.content });
|
|
91
91
|
} else if (node.type === 'text') {
|
|
92
92
|
this.queue.push(node as TypstNode)
|
|
93
93
|
} else if (node.type === 'supsub') {
|
|
94
|
-
let { base, sup, sub } = node.
|
|
94
|
+
let { base, sup, sub } = node.data as TexSupsubData;
|
|
95
95
|
|
|
96
96
|
// Special logic for overbrace
|
|
97
97
|
if (base && base.type === 'unaryFunc' && base.content === '\\overbrace' && sup) {
|
|
@@ -103,7 +103,7 @@ export class TypstWriter {
|
|
|
103
103
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (
|
|
106
|
+
if (base.type === 'empty') {
|
|
107
107
|
this.queue.push({ type: 'text', content: '' });
|
|
108
108
|
} else {
|
|
109
109
|
this.appendWithBracketsIfNeeded(base);
|
|
@@ -134,7 +134,7 @@ export class TypstWriter {
|
|
|
134
134
|
} else if (node.type === 'leftright') {
|
|
135
135
|
const [left, body, right] = node.args!;
|
|
136
136
|
// These pairs will be handled by Typst compiler by default. No need to add lr()
|
|
137
|
-
if (["[]", "()", "{}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
|
|
137
|
+
if (["[]", "()", "\\{\\}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
|
|
138
138
|
this.append(left);
|
|
139
139
|
this.append(body);
|
|
140
140
|
this.append(right);
|
|
@@ -163,12 +163,12 @@ export class TypstWriter {
|
|
|
163
163
|
} else if (node.type === 'unaryFunc') {
|
|
164
164
|
const func_symbol: TypstNode = { type: 'symbol', content: node.content };
|
|
165
165
|
const arg0 = node.args![0];
|
|
166
|
-
if (node.content === '\\sqrt' && node.
|
|
166
|
+
if (node.content === '\\sqrt' && node.data) {
|
|
167
167
|
func_symbol.content = 'root';
|
|
168
168
|
this.queue.push(func_symbol);
|
|
169
169
|
this.insideFunctionDepth ++;
|
|
170
170
|
this.queue.push({ type: 'atom', content: '('});
|
|
171
|
-
this.append(node.
|
|
171
|
+
this.append(node.data as TexSqrtData); // the number of times to take the root
|
|
172
172
|
this.queue.push({ type: 'atom', content: ','});
|
|
173
173
|
this.append(arg0);
|
|
174
174
|
this.queue.push({ type: 'atom', content: ')'});
|
|
@@ -189,7 +189,7 @@ export class TypstWriter {
|
|
|
189
189
|
return;
|
|
190
190
|
} else if (node.content === '\\mathbb') {
|
|
191
191
|
const body = node.args![0];
|
|
192
|
-
if (body.type === '
|
|
192
|
+
if (body.type === 'element' && /^[A-Z]$/.test(body.content)) {
|
|
193
193
|
// \mathbb{R} -> RR
|
|
194
194
|
this.queue.push({ type: 'symbol', content: body.content + body.content});
|
|
195
195
|
return;
|
|
@@ -210,14 +210,6 @@ export class TypstWriter {
|
|
|
210
210
|
if (this.preferTypstIntrinsic && TYPST_INTRINSIC_SYMBOLS.includes(text)) {
|
|
211
211
|
// e.g. we prefer just sech over op("sech")
|
|
212
212
|
this.queue.push({ type: 'symbol', content: text});
|
|
213
|
-
} else if (text.startsWith('SyMb01-')) {
|
|
214
|
-
// special hacks made in parseTex()
|
|
215
|
-
const special_symbol = text.substring(7);
|
|
216
|
-
if (special_symbol === 'newline') {
|
|
217
|
-
this.queue.push({ type: 'newline', content: '\n'});
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
this.queue.push({ type: 'symbol', content: '\\' + special_symbol});
|
|
221
213
|
} else {
|
|
222
214
|
this.queue.push({ type: 'symbol', content: 'op' });
|
|
223
215
|
this.queue.push({ type: 'atom', content: '('});
|
|
@@ -233,54 +225,67 @@ export class TypstWriter {
|
|
|
233
225
|
this.append(arg0);
|
|
234
226
|
this.queue.push({ type: 'atom', content: ')'});
|
|
235
227
|
this.insideFunctionDepth --;
|
|
236
|
-
} else if (node.type === '
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
228
|
+
} else if (node.type === 'newline') {
|
|
229
|
+
this.queue.push({ type: 'newline', content: '\n'});
|
|
230
|
+
return;
|
|
231
|
+
} else if (node.type === 'beginend') {
|
|
232
|
+
if (node.content!.startsWith('align')) {
|
|
233
|
+
// align, align*, alignat, alignat*, aligned, etc.
|
|
234
|
+
const matrix = node.data as TexNode[][];
|
|
235
|
+
matrix.forEach((row, i) => {
|
|
236
|
+
row.forEach((cell, j) => {
|
|
237
|
+
if (j > 0) {
|
|
238
|
+
this.queue.push({ type: 'atom', content: '&' });
|
|
239
|
+
}
|
|
240
|
+
this.append(cell);
|
|
241
|
+
});
|
|
242
|
+
if (i < matrix.length - 1) {
|
|
243
|
+
this.queue.push({ type: 'symbol', content: '\\\\' });
|
|
242
244
|
}
|
|
243
|
-
this.append(cell);
|
|
244
245
|
});
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// There is a leading & in row
|
|
258
|
-
if (cell.type === 'ordgroup' && cell.args!.length === 0) {
|
|
259
|
-
this.queue.push({ type: 'atom', content: ',' });
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
// if (j == 0 && cell.type === 'newline' && cell.content === '\n') {
|
|
263
|
-
// return;
|
|
264
|
-
// }
|
|
265
|
-
this.append(cell);
|
|
266
|
-
// cell.args!.forEach((n) => this.append(n));
|
|
267
|
-
if (j < row.length - 1) {
|
|
268
|
-
this.queue.push({ type: 'atom', content: ',' });
|
|
269
|
-
} else {
|
|
270
|
-
if (i < matrix.length - 1) {
|
|
271
|
-
this.queue.push({ type: 'atom', content: ';' });
|
|
246
|
+
} else {
|
|
247
|
+
const matrix = node.data as TexNode[][];
|
|
248
|
+
this.queue.push({ type: 'symbol', content: 'mat' });
|
|
249
|
+
this.insideFunctionDepth ++;
|
|
250
|
+
this.queue.push({ type: 'atom', content: '('});
|
|
251
|
+
this.queue.push({type: 'symbol', content: 'delim: #none, '});
|
|
252
|
+
matrix.forEach((row, i) => {
|
|
253
|
+
row.forEach((cell, j) => {
|
|
254
|
+
// There is a leading & in row
|
|
255
|
+
if (cell.type === 'ordgroup' && cell.args!.length === 0) {
|
|
256
|
+
this.queue.push({ type: 'atom', content: ',' });
|
|
257
|
+
return;
|
|
272
258
|
}
|
|
273
|
-
|
|
259
|
+
// if (j == 0 && cell.type === 'newline' && cell.content === '\n') {
|
|
260
|
+
// return;
|
|
261
|
+
// }
|
|
262
|
+
this.append(cell);
|
|
263
|
+
// cell.args!.forEach((n) => this.append(n));
|
|
264
|
+
if (j < row.length - 1) {
|
|
265
|
+
this.queue.push({ type: 'atom', content: ',' });
|
|
266
|
+
} else {
|
|
267
|
+
if (i < matrix.length - 1) {
|
|
268
|
+
this.queue.push({ type: 'atom', content: ';' });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
274
272
|
});
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
273
|
+
this.queue.push({ type: 'atom', content: ')'});
|
|
274
|
+
this.insideFunctionDepth --;
|
|
275
|
+
}
|
|
276
|
+
} else if (node.type === 'matrix') {
|
|
278
277
|
} else if (node.type === 'unknownMacro') {
|
|
279
278
|
if (this.nonStrict) {
|
|
280
279
|
this.queue.push({ type: 'symbol', content: node.content });
|
|
281
280
|
} else {
|
|
282
281
|
throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
|
|
283
282
|
}
|
|
283
|
+
} else if (node.type === 'control') {
|
|
284
|
+
if (node.content === '\\\\') {
|
|
285
|
+
this.queue.push({ type: 'symbol', content: node.content });
|
|
286
|
+
} else {
|
|
287
|
+
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
|
|
288
|
+
}
|
|
284
289
|
} else if (node.type === 'comment') {
|
|
285
290
|
this.queue.push({ type: 'comment', content: node.content });
|
|
286
291
|
} else {
|
|
@@ -322,10 +327,7 @@ export class TypstWriter {
|
|
|
322
327
|
}
|
|
323
328
|
|
|
324
329
|
private appendWithBracketsIfNeeded(node: TexNode): boolean {
|
|
325
|
-
const
|
|
326
|
-
const is_single_function = (node.type === 'unaryFunc' || node.type === 'binaryFunc' || node.type === 'leftright');
|
|
327
|
-
|
|
328
|
-
const is_single = ['atom', 'symbol', 'unaryFunc', 'binaryFunc', 'leftright'].includes(node.type);
|
|
330
|
+
const is_single = ['symbol', 'element', 'unaryFunc', 'binaryFunc', 'leftright'].includes(node.type);
|
|
329
331
|
if (is_single) {
|
|
330
332
|
this.append(node);
|
|
331
333
|
} else {
|
package/tsconfig.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
|
-
"target": "
|
|
14
|
+
"target": "es2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
15
15
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
16
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
17
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|