tex2typst 0.3.29 → 0.4.1
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.d.ts +13 -9
- package/dist/index.js +233 -224
- package/dist/tex2typst.min.js +12 -13
- package/package.json +2 -2
- package/src/convert.ts +88 -36
- package/src/exposed-types.ts +13 -9
- package/src/generic.ts +6 -6
- package/src/index.ts +23 -12
- package/src/map.ts +1 -0
- package/src/tex-parser.ts +19 -47
- package/src/tex-tokenizer.ts +1 -0
- package/src/tex-types.ts +3 -1
- package/src/tex-writer.ts +10 -1
- package/src/typst-parser.ts +114 -160
- package/tests/cheat-sheet.test.ts +0 -42
- package/tests/cheat-sheet.toml +0 -304
- package/tests/example.ts +0 -15
- package/tests/general-symbols.test.ts +0 -22
- package/tests/general-symbols.toml +0 -755
- package/tests/integration-tex2typst.yaml +0 -89
- package/tests/struct-bidirection.yaml +0 -194
- package/tests/struct-tex2typst.yaml +0 -457
- package/tests/struct-typst2tex.yaml +0 -412
- package/tests/symbol.yml +0 -126
- package/tests/test-common.ts +0 -26
- package/tests/tex-parser.test.ts +0 -97
- package/tests/tex-to-typst.test.ts +0 -136
- package/tests/typst-parser.test.ts +0 -134
- package/tests/typst-to-tex.test.ts +0 -76
- /package/src/{util.ts → utils.ts} +0 -0
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { describe, it, test, expect } from 'vitest';
|
|
2
|
-
import { tokenize_tex } from '../src/tex-tokenizer';
|
|
3
|
-
import { parseTex } from '../src/tex-parser';
|
|
4
|
-
import { tex2typst } from '../src/index';
|
|
5
|
-
import { TypstWriterError } from '../src/typst-writer';
|
|
6
|
-
import { TexNode, TexToken } from '../src/tex-types';
|
|
7
|
-
import type { Tex2TypstOptions } from '../src/exposed-types';
|
|
8
|
-
import { loadTestCases, TestCase } from './test-common';
|
|
9
|
-
import { ConverterError } from '../src/convert';
|
|
10
|
-
|
|
11
|
-
describe('options', () => {
|
|
12
|
-
it('nonStrict = false', function () {
|
|
13
|
-
const input = '\\nonExistentCommand';
|
|
14
|
-
// must throw error
|
|
15
|
-
expect(() => tex2typst(input, { nonStrict: false })).toThrowError(ConverterError);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
it('fracToSlash = true', function () {
|
|
20
|
-
const input = '\\frac{a}{b}';
|
|
21
|
-
const expected = 'a/b';
|
|
22
|
-
const res = tex2typst(input, { fracToSlash: true });
|
|
23
|
-
expect(res).toEqual(expected);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('fracToSlash = false', function () {
|
|
27
|
-
const input = '\\frac{a}{b}';
|
|
28
|
-
const expected = 'frac(a, b)';
|
|
29
|
-
const res = tex2typst(input, { fracToSlash: false });
|
|
30
|
-
expect(res).toEqual(expected);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
it('non-ASCII text', function () {
|
|
35
|
-
const input = 'a + b = \\text{こにちは、世界}';
|
|
36
|
-
const expected = 'a + b = "こにちは、世界"';
|
|
37
|
-
const res = tex2typst(input);
|
|
38
|
-
expect(res).toEqual(expected);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('preferShorthands = true', function () {
|
|
42
|
-
const map = new Map<string, string>([
|
|
43
|
-
['a \\rightarrow b', 'a -> b'],
|
|
44
|
-
['a \\to b', 'a -> b'],
|
|
45
|
-
['a \\implies b', 'a ==> b'],
|
|
46
|
-
['a \\iff b', 'a <==> b'],
|
|
47
|
-
['a \\ll b', 'a << b'],
|
|
48
|
-
['a \\gg b', 'a >> b'],
|
|
49
|
-
|
|
50
|
-
]);
|
|
51
|
-
for(const [input, expected] of map.entries()) {
|
|
52
|
-
const res = tex2typst(input, { preferShorthands: true });
|
|
53
|
-
expect(res).toEqual(expected);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('preferShorthands = false', function () {
|
|
58
|
-
const map = new Map<string, string>([
|
|
59
|
-
['a \\rightarrow b', 'a arrow.r b'],
|
|
60
|
-
['a \\to b', 'a arrow.r b'],
|
|
61
|
-
['a \\implies b', 'a arrow.r.double.long b'],
|
|
62
|
-
['a \\iff b', 'a arrow.l.r.double.long b'],
|
|
63
|
-
['a \\ll b', 'a lt.double b'],
|
|
64
|
-
['a \\gg b', 'a gt.double b'],
|
|
65
|
-
|
|
66
|
-
]);
|
|
67
|
-
for(const [input, expected] of map.entries()) {
|
|
68
|
-
const res = tex2typst(input, { preferShorthands: false });
|
|
69
|
-
expect(res).toEqual(expected);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it ('customTexMacros', function () {
|
|
74
|
-
const input = '\\myop y=\\sgn(x)';
|
|
75
|
-
const expected = 'op("myop") y = op("sgn")(x)';
|
|
76
|
-
const res = tex2typst(input, { customTexMacros: {
|
|
77
|
-
'\\myop': '\\operatorname{myop}',
|
|
78
|
-
'\\sgn': '\\operatorname{sgn}',
|
|
79
|
-
} });
|
|
80
|
-
expect(res).toEqual(expected);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it ('customTexMacros 2', function () {
|
|
84
|
-
const input = '123 \\foo 456';
|
|
85
|
-
const expected = '123 root(3, x) 456';
|
|
86
|
-
const res = tex2typst(input, { customTexMacros: {
|
|
87
|
-
'\\foo': '\\sqrt[3]{x}',
|
|
88
|
-
} });
|
|
89
|
-
expect(res).toEqual(expected);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const caseFiles = ["struct-tex2typst.yaml", "symbol.yml", "struct-bidirection.yaml", "integration-tex2typst.yaml"];
|
|
95
|
-
|
|
96
|
-
caseFiles.forEach((ymlFilename) => {
|
|
97
|
-
const suite = loadTestCases(ymlFilename);
|
|
98
|
-
describe(ymlFilename, () => {
|
|
99
|
-
suite.cases.forEach((c: TestCase) => {
|
|
100
|
-
test(c.title, function() {
|
|
101
|
-
const {tex, typst} = c;
|
|
102
|
-
let tokens: null | TexToken[] = null;
|
|
103
|
-
let tex_node: null | TexNode = null;
|
|
104
|
-
let result: null | string = null;
|
|
105
|
-
try {
|
|
106
|
-
const settings: Tex2TypstOptions = {
|
|
107
|
-
nonStrict: c.nonStrict? c.nonStrict: false,
|
|
108
|
-
preferShorthands: c.preferShorthands !== undefined? c.preferShorthands: true,
|
|
109
|
-
inftyToOo: c.inftyToOo !== undefined? c.inftyToOo: false,
|
|
110
|
-
customTexMacros: c.customTexMacros? c.customTexMacros: {},
|
|
111
|
-
};
|
|
112
|
-
tokens = tokenize_tex(tex);
|
|
113
|
-
tex_node = parseTex(tex, settings.customTexMacros!);
|
|
114
|
-
result = tex2typst(tex, settings);
|
|
115
|
-
if (result !== typst) {
|
|
116
|
-
console.log(`====== 😭 Wrong ======`);
|
|
117
|
-
console.log(tex);
|
|
118
|
-
console.log(tokens);
|
|
119
|
-
console.dir(tex_node, {depth: null});
|
|
120
|
-
}
|
|
121
|
-
expect(result).toBe(typst);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
console.log(`====== 😭 Error ======`);
|
|
124
|
-
if (e instanceof TypstWriterError) {
|
|
125
|
-
console.log(e.node);
|
|
126
|
-
}
|
|
127
|
-
if (tex_node !== null) {
|
|
128
|
-
console.dir(tex_node, {depth: null});
|
|
129
|
-
}
|
|
130
|
-
console.log(tex);
|
|
131
|
-
throw e;
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { tokenize_typst } from '../src/typst-tokenizer';
|
|
3
|
-
import { TypstParser } from '../src/typst-parser';
|
|
4
|
-
import { TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstSupsub, TypstTerminal, TypstToken, TypstTokenType } from '../src/typst-types';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
describe('typst-tokenizer', () => {
|
|
8
|
-
it('a + b', function () {
|
|
9
|
-
const res = tokenize_typst('a + b');
|
|
10
|
-
expect(res).toEqual([
|
|
11
|
-
new TypstToken(TypstTokenType.ELEMENT, 'a'),
|
|
12
|
-
new TypstToken(TypstTokenType.SPACE, ' '),
|
|
13
|
-
new TypstToken(TypstTokenType.ELEMENT, '+'),
|
|
14
|
-
new TypstToken(TypstTokenType.SPACE, ' '),
|
|
15
|
-
new TypstToken(TypstTokenType.ELEMENT, 'b'),
|
|
16
|
-
]);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('a (x)', function () {
|
|
20
|
-
const res = tokenize_typst('a (x)');
|
|
21
|
-
expect(res).toEqual([
|
|
22
|
-
new TypstToken(TypstTokenType.ELEMENT, 'a'),
|
|
23
|
-
new TypstToken(TypstTokenType.SPACE, ' '),
|
|
24
|
-
new TypstToken(TypstTokenType.ELEMENT, '('),
|
|
25
|
-
new TypstToken(TypstTokenType.ELEMENT, 'x'),
|
|
26
|
-
new TypstToken(TypstTokenType.ELEMENT, ')'),
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('f(x)', function () {
|
|
31
|
-
const res = tokenize_typst('f(x)');
|
|
32
|
-
expect(res).toEqual([
|
|
33
|
-
new TypstToken(TypstTokenType.ELEMENT, 'f'),
|
|
34
|
-
new TypstToken(TypstTokenType.ELEMENT, '('),
|
|
35
|
-
new TypstToken(TypstTokenType.ELEMENT, 'x'),
|
|
36
|
-
new TypstToken(TypstTokenType.ELEMENT, ')'),
|
|
37
|
-
]);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('comment', function() {
|
|
41
|
-
const res = tokenize_typst('a // comment');
|
|
42
|
-
expect(res).toEqual([
|
|
43
|
-
new TypstToken(TypstTokenType.ELEMENT, 'a'),
|
|
44
|
-
new TypstToken(TypstTokenType.SPACE, ' '),
|
|
45
|
-
new TypstToken(TypstTokenType.COMMENT, ' comment'),
|
|
46
|
-
]);
|
|
47
|
-
})
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('typst-parser', () => {
|
|
51
|
-
const parser = new TypstParser();
|
|
52
|
-
it('a + b', function () {
|
|
53
|
-
const tokens = tokenize_typst('a + b');
|
|
54
|
-
const res = parser.parse(tokens);
|
|
55
|
-
expect(res).toEqual(new TypstGroup([
|
|
56
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'a')),
|
|
57
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
58
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '+')),
|
|
59
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
60
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'b')),
|
|
61
|
-
]));
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('a (x)', function () {
|
|
65
|
-
const tokens = tokenize_typst('a (x)');
|
|
66
|
-
const res = parser.parse(tokens);
|
|
67
|
-
expect(res).toEqual(new TypstGroup([
|
|
68
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'a')),
|
|
69
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
70
|
-
new TypstLeftright(null, {
|
|
71
|
-
body: new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'x')),
|
|
72
|
-
left: new TypstToken(TypstTokenType.ELEMENT, '('),
|
|
73
|
-
right: new TypstToken(TypstTokenType.ELEMENT, ')')
|
|
74
|
-
})
|
|
75
|
-
]));
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('f(x)', function () {
|
|
79
|
-
const tokens = tokenize_typst('f(x)');
|
|
80
|
-
const res = parser.parse(tokens);
|
|
81
|
-
expect(res).toEqual(new TypstFuncCall(new TypstToken(TypstTokenType.ELEMENT, 'f'), [
|
|
82
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'x')),
|
|
83
|
-
]));
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('root(x, 3)', function () {
|
|
87
|
-
const tokens = tokenize_typst('root(x, 3)');
|
|
88
|
-
const res = parser.parse(tokens);
|
|
89
|
-
expect(res).toEqual(new TypstFuncCall(new TypstToken(TypstTokenType.SYMBOL, 'root'), [
|
|
90
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'x')),
|
|
91
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '3')),
|
|
92
|
-
]));
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('lim_(x arrow.r 0)', function () {
|
|
96
|
-
const tokens = tokenize_typst('lim_(x arrow.r 0)');
|
|
97
|
-
const res = parser.parse(tokens);
|
|
98
|
-
expect(res).toEqual(new TypstSupsub({
|
|
99
|
-
base: new TypstTerminal(new TypstToken(TypstTokenType.SYMBOL, 'lim')),
|
|
100
|
-
sub: new TypstGroup([
|
|
101
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'x')),
|
|
102
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
103
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SYMBOL, 'arrow.r')),
|
|
104
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
105
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '0')),
|
|
106
|
-
]),
|
|
107
|
-
sup: null,
|
|
108
|
-
}));
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('a -> b', function () {
|
|
112
|
-
const tokens = tokenize_typst('a -> b');
|
|
113
|
-
const res = parser.parse(tokens);
|
|
114
|
-
expect(res).toEqual(new TypstGroup([
|
|
115
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'a')),
|
|
116
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
117
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SYMBOL, 'arrow.r')),
|
|
118
|
-
new TypstTerminal(new TypstToken(TypstTokenType.SPACE, ' ')),
|
|
119
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, 'b')),
|
|
120
|
-
]));
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('1/(2/3)', function () {
|
|
124
|
-
const tokens = tokenize_typst('1/(2/3)');
|
|
125
|
-
const res = parser.parse(tokens);
|
|
126
|
-
expect(res).toEqual(new TypstFraction([
|
|
127
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '1')),
|
|
128
|
-
new TypstFraction([
|
|
129
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '2')),
|
|
130
|
-
new TypstTerminal(new TypstToken(TypstTokenType.ELEMENT, '3')),
|
|
131
|
-
]),
|
|
132
|
-
]));
|
|
133
|
-
});
|
|
134
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { describe, it, test, expect } from 'vitest';
|
|
3
|
-
import { parseTypst } from '../src/typst-parser';
|
|
4
|
-
import { TexWriter } from '../src/tex-writer';
|
|
5
|
-
import { convert_typst_node_to_tex } from '../src/convert';
|
|
6
|
-
import { loadTestCases, TestCase } from './test-common';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
describe('examples', () => {
|
|
11
|
-
it('a + b', function () {
|
|
12
|
-
const typst_node = parseTypst('a + b');
|
|
13
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
14
|
-
const writer = new TexWriter();
|
|
15
|
-
writer.append(tex_node);
|
|
16
|
-
const res = writer.finalize();
|
|
17
|
-
expect(res).toEqual('a + b');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('sqrt(x)', function () {
|
|
21
|
-
const typst_node = parseTypst('sqrt(x)');
|
|
22
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
23
|
-
const writer = new TexWriter();
|
|
24
|
-
writer.append(tex_node);
|
|
25
|
-
const res = writer.finalize();
|
|
26
|
-
expect(res).toEqual('\\sqrt{x}');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('integral_a^b f(x) dif x', function () {
|
|
30
|
-
const typst_node = parseTypst('integral_a^b f(x) dif x');
|
|
31
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
32
|
-
const writer = new TexWriter();
|
|
33
|
-
writer.append(tex_node);
|
|
34
|
-
const res = writer.finalize();
|
|
35
|
-
expect(res).toEqual('\\int_a^b f(x) \\mathrm{d} x');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('lr({a + 1/3))', function () {
|
|
39
|
-
const typst_node = parseTypst('lr({a + 1/3))');
|
|
40
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
41
|
-
const writer = new TexWriter();
|
|
42
|
-
writer.append(tex_node);
|
|
43
|
-
const res = writer.finalize();
|
|
44
|
-
expect(res).toEqual('\\left\\{a + \\frac{1}{3} \\right)');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
describe('struct-typst2tex.yaml', function () {
|
|
51
|
-
const suite = loadTestCases('struct-typst2tex.yaml');
|
|
52
|
-
suite.cases.forEach((c: TestCase) => {
|
|
53
|
-
test(c.title, function () {
|
|
54
|
-
const typst_node = parseTypst(c.typst);
|
|
55
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
56
|
-
const writer = new TexWriter();
|
|
57
|
-
writer.append(tex_node);
|
|
58
|
-
const res = writer.finalize();
|
|
59
|
-
expect(res).toEqual(c.tex);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('struct-bidirection.yaml', function () {
|
|
65
|
-
const suite = loadTestCases('struct-bidirection.yaml');
|
|
66
|
-
suite.cases.forEach((c: TestCase) => {
|
|
67
|
-
test(c.title, function () {
|
|
68
|
-
const typst_node = parseTypst(c.typst);
|
|
69
|
-
const tex_node = convert_typst_node_to_tex(typst_node);
|
|
70
|
-
const writer = new TexWriter();
|
|
71
|
-
writer.append(tex_node);
|
|
72
|
-
const res = writer.finalize();
|
|
73
|
-
expect(res).toEqual(c.tex);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
});
|
|
File without changes
|