xmmath 1.0.9 → 1.1.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/.github/workflows/build.yml +5 -3
- package/AGENTS.md +33 -0
- package/biome.json +34 -0
- package/dist/xmmath.es.js +5304 -3219
- package/dist/xmmath.es.js.map +1 -1
- package/dist/xmmath.umd.js +3852 -2288
- package/dist/xmmath.umd.js.map +1 -1
- package/package.json +38 -27
- package/pnpm-workspace.yaml +2 -0
- package/readme.md +3 -2
- package/src/ast.ts +161 -0
- package/src/emoji.json +2122 -1456
- package/src/main.ts +905 -1868
- package/src/normalize.ts +1381 -0
- package/src/symbols.json +1726 -827
- package/src/vdom.ts +173 -0
- package/tsconfig.json +11 -99
- package/vite.config.js +12 -9
package/package.json
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
2
|
+
"name": "xmmath",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./dist/xmmath.umd.js",
|
|
6
|
+
"module": "./dist/xmmath.es.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/xmmath.es.js",
|
|
10
|
+
"require": "./dist/xmmath.umd.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/xushengfeng/xmmath",
|
|
14
|
+
"repository": {
|
|
15
|
+
"url": "https://github.com/xushengfeng/xmmath"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"types": "./src/main.ts",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"review": "vite --host 0.0.0.0 --open /test/review/index.html",
|
|
23
|
+
"sync:symbols": "node test/symbols/gen.mjs",
|
|
24
|
+
"render:typst": "node test/typst/render.mjs",
|
|
25
|
+
"render:xmmath": "node test/xmmath/render.mjs",
|
|
26
|
+
"dev": "vite --host 0.0.0.0",
|
|
27
|
+
"build": "tsc && vite build",
|
|
28
|
+
"preview": "vite preview"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "Apache-2.0",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@biomejs/biome": "^2.5.14",
|
|
35
|
+
"jsdom": "^30.1.1",
|
|
36
|
+
"typescript": "^5.4.5",
|
|
37
|
+
"vite": "^4.3.9",
|
|
38
|
+
"vitest": "^1.6.1"
|
|
39
|
+
}
|
|
29
40
|
}
|
package/readme.md
CHANGED
|
@@ -87,11 +87,12 @@ For more details, please go to [typst docs](https://typst.app/docs) for more inf
|
|
|
87
87
|
## 使用(use)
|
|
88
88
|
|
|
89
89
|
```typescript
|
|
90
|
-
xmmath.toMMLHTML("e^(i pi)=-1"); // 输出html
|
|
90
|
+
xmmath.toMMLHTML("e^(i pi)=-1"); // 输出html(默认块级 display="block")
|
|
91
|
+
xmmath.toMMLHTML("e^(i pi)=-1", true); // 行内:不写 display 属性
|
|
91
92
|
```
|
|
92
93
|
|
|
93
94
|
```typescript
|
|
94
|
-
xmmath.toMML("e^(i pi)=-1"); // 输出mathml
|
|
95
|
+
xmmath.toMML("e^(i pi)=-1"); // 输出mathml元素(第二个参数同样可传 inline)
|
|
95
96
|
```
|
|
96
97
|
|
|
97
98
|
```typescript
|
package/src/ast.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
export type vtype =
|
|
2
|
+
| ""
|
|
3
|
+
| "str"
|
|
4
|
+
| "v"
|
|
5
|
+
| "f"
|
|
6
|
+
| "blank"
|
|
7
|
+
| "group"
|
|
8
|
+
| "group1"
|
|
9
|
+
| "sharp";
|
|
10
|
+
export type tree = {
|
|
11
|
+
type: vtype;
|
|
12
|
+
value: string;
|
|
13
|
+
children?: tree;
|
|
14
|
+
esc?: boolean;
|
|
15
|
+
kh?: string;
|
|
16
|
+
src?: string;
|
|
17
|
+
}[];
|
|
18
|
+
|
|
19
|
+
const Segmenter = Intl.Segmenter;
|
|
20
|
+
const segmenter = new Segmenter("emoji", { granularity: "grapheme" });
|
|
21
|
+
|
|
22
|
+
export const init_c: { emoji: (str: string) => string } = {
|
|
23
|
+
emoji: null,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function ast(str: string): tree {
|
|
27
|
+
const v = /[a-zA-Z]/;
|
|
28
|
+
const kh = /[(){}[\]]/;
|
|
29
|
+
const khl = /[({[]/;
|
|
30
|
+
const khr = /[)}\]]/;
|
|
31
|
+
const blank = /^[ \t\n\r]+$/;
|
|
32
|
+
let type: vtype = "";
|
|
33
|
+
let ignore: false | "line" | "block" = false;
|
|
34
|
+
const o: tree = [];
|
|
35
|
+
const p_tree: { tree: tree; close: boolean }[] = [];
|
|
36
|
+
let now_tree = o;
|
|
37
|
+
let tmp_str = "";
|
|
38
|
+
|
|
39
|
+
str = str.replace(/(\\u\{[\dA-Fa-f]+\})/g, (v) => {
|
|
40
|
+
const codePoint = parseInt(v.slice(3, -1), 16);
|
|
41
|
+
return String.fromCodePoint(codePoint);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
let strl = init_c.emoji
|
|
45
|
+
? init_c.emoji(str)
|
|
46
|
+
: Array.from(segmenter.segment(str)).map((w) => w.segment);
|
|
47
|
+
const strl2 = [];
|
|
48
|
+
for (const i of strl) {
|
|
49
|
+
if (i.length > 1 && i.includes(",")) strl2.push(...i);
|
|
50
|
+
else strl2.push(i);
|
|
51
|
+
}
|
|
52
|
+
strl = strl2;
|
|
53
|
+
|
|
54
|
+
for (let i = 0; i < strl.length; i++) {
|
|
55
|
+
const t = strl[i];
|
|
56
|
+
const next = strl[i + 1];
|
|
57
|
+
if (t === "/" && next === "/") ignore = "line";
|
|
58
|
+
if (ignore === "line" && t === "\n") {
|
|
59
|
+
ignore = false;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (t === "/" && next === "*") ignore = "block";
|
|
63
|
+
if (ignore === "block" && t === "*" && next === "/") {
|
|
64
|
+
i++;
|
|
65
|
+
ignore = false;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (ignore) continue;
|
|
70
|
+
|
|
71
|
+
if (type === "blank" && !t.match(blank)) {
|
|
72
|
+
now_tree.push({ type, value: "" });
|
|
73
|
+
type = "";
|
|
74
|
+
}
|
|
75
|
+
if (t === '"' && strl[i - 1] !== "\\") {
|
|
76
|
+
if (type !== "str") {
|
|
77
|
+
type = "str";
|
|
78
|
+
} else {
|
|
79
|
+
now_tree.push({ type, value: tmp_str });
|
|
80
|
+
type = "";
|
|
81
|
+
tmp_str = "";
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (type === "str") {
|
|
86
|
+
tmp_str += t;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (t.match(blank)) {
|
|
91
|
+
type = "blank";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (t === "#") {
|
|
95
|
+
now_tree.push({ type: "sharp", value: "" });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
type === "" &&
|
|
101
|
+
(!strl[i - 1] || !strl[i - 1].match(v)) &&
|
|
102
|
+
(!strl[i + 1] || !strl[i + 1].match(v)) &&
|
|
103
|
+
!t.match(kh)
|
|
104
|
+
) {
|
|
105
|
+
now_tree.push({ type: "v", value: t });
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (type === "" && !t.match(v) && !t.match(kh)) {
|
|
109
|
+
now_tree.push({ type: "v", value: t });
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
((strl[i - 1] && strl[i - 1].match(v)) ||
|
|
115
|
+
(strl[i + 1] && strl[i + 1].match(v))) &&
|
|
116
|
+
t.match(v)
|
|
117
|
+
) {
|
|
118
|
+
type = "f";
|
|
119
|
+
}
|
|
120
|
+
if (type === "f") {
|
|
121
|
+
tmp_str += t;
|
|
122
|
+
}
|
|
123
|
+
if (type === "f" && (!strl[i + 1] || !strl[i + 1].match(v))) {
|
|
124
|
+
now_tree.push({ type, value: tmp_str });
|
|
125
|
+
type = "";
|
|
126
|
+
tmp_str = "";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (t.match(khl)) {
|
|
130
|
+
if (strl[i - 1] === "\\") {
|
|
131
|
+
now_tree.push({ type: "v", value: t, esc: true });
|
|
132
|
+
} else {
|
|
133
|
+
// 开括号一律起组,直到遇到闭括号;到行尾仍没遇到(typst
|
|
134
|
+
// `math_delimited` 走到 eof 的分支)就留成未闭合组,由渲染
|
|
135
|
+
// 阶段只画开括号。旧实现把未配对的开括号退化成普通字符,
|
|
136
|
+
// 会让 `1/(2 (x)` 的分母只剩一个 `(`。
|
|
137
|
+
p_tree.push({ tree: now_tree, close: false });
|
|
138
|
+
now_tree.push({ type: "group", value: tmp_str, children: [], kh: t });
|
|
139
|
+
now_tree = now_tree.at(-1).children;
|
|
140
|
+
tmp_str = "";
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (t.match(khr)) {
|
|
145
|
+
if (strl[i - 1] === "\\") {
|
|
146
|
+
now_tree.push({ type: "v", value: t, esc: true });
|
|
147
|
+
} else if (p_tree.at(-1)) {
|
|
148
|
+
if (p_tree.at(-1).close === false) {
|
|
149
|
+
p_tree.at(-1).close = true;
|
|
150
|
+
now_tree = p_tree.at(-1).tree;
|
|
151
|
+
now_tree.at(-1).kh += t;
|
|
152
|
+
p_tree.pop();
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
now_tree.push({ type: "v", value: t });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return o;
|
|
161
|
+
}
|