@markupme/core 0.1.0 → 0.1.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/THIRD-PARTY-NOTICES.md +37 -0
- package/dist/parse.js +1 -1
- package/dist/plugins/math-syntax.d.ts +20 -0
- package/dist/plugins/math-syntax.js +279 -0
- package/dist/plugins/math.d.ts +2 -0
- package/dist/plugins/math.js +17 -0
- package/dist/render/html.js +2 -4
- package/dist/render/katex.d.ts +13 -0
- package/dist/render/katex.js +79 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
`@markupme/core` contains code ported to TypeScript from these MIT-licensed projects:
|
|
4
|
+
|
|
5
|
+
| File | Ported from | Copyright |
|
|
6
|
+
| ---- | ----------- | --------- |
|
|
7
|
+
| `src/render/katex.ts` | [rehype-katex](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex) 7.0.1 | Copyright (c) Junyoung Choi <fluke8259@gmail.com> |
|
|
8
|
+
| `src/plugins/math.ts` | [remark-math](https://github.com/remarkjs/remark-math/tree/main/packages/remark-math) 6.0.0 | Copyright (c) Junyoung Choi <fluke8259@gmail.com> |
|
|
9
|
+
| `src/plugins/math-syntax.ts` | [micromark-extension-math](https://github.com/micromark/micromark-extension-math) 3.1.0 | Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com> |
|
|
10
|
+
|
|
11
|
+
All three are distributed under the MIT License:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
(The MIT License)
|
|
15
|
+
|
|
16
|
+
Copyright (c) Junyoung Choi <fluke8259@gmail.com>
|
|
17
|
+
Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
20
|
+
a copy of this software and associated documentation files (the
|
|
21
|
+
'Software'), to deal in the Software without restriction, including
|
|
22
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
23
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
24
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
25
|
+
the following conditions:
|
|
26
|
+
|
|
27
|
+
The above copyright notice and this permission notice shall be
|
|
28
|
+
included in all copies or substantial portions of the Software.
|
|
29
|
+
|
|
30
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
31
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
32
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
33
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
34
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
35
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
36
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
37
|
+
```
|
package/dist/parse.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import remarkDirective from 'remark-directive';
|
|
2
2
|
import remarkFrontmatter from 'remark-frontmatter';
|
|
3
3
|
import remarkGfm from 'remark-gfm';
|
|
4
|
-
import remarkMath from 'remark-math';
|
|
5
4
|
import remarkParse from 'remark-parse';
|
|
6
5
|
import { unified } from 'unified';
|
|
7
6
|
import { annotateAlerts } from './plugins/alerts.js';
|
|
8
7
|
import { normalizeDirectives } from './plugins/directives.js';
|
|
9
8
|
import { readFrontmatter } from './plugins/frontmatter.js';
|
|
10
9
|
import { addHeadingIds } from './plugins/headings.js';
|
|
10
|
+
import { remarkMath } from './plugins/math.js';
|
|
11
11
|
import { insertToc } from './plugins/toc.js';
|
|
12
12
|
import { SCHEMA_VERSION, } from './types.js';
|
|
13
13
|
/** Syntax extensions shared by the parser and the serializer, so round trips keep every construct. */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Extension } from 'micromark-util-types';
|
|
2
|
+
declare module 'micromark-util-types' {
|
|
3
|
+
interface TokenTypeMap {
|
|
4
|
+
mathFlow: 'mathFlow';
|
|
5
|
+
mathFlowFence: 'mathFlowFence';
|
|
6
|
+
mathFlowFenceMeta: 'mathFlowFenceMeta';
|
|
7
|
+
mathFlowFenceSequence: 'mathFlowFenceSequence';
|
|
8
|
+
mathFlowValue: 'mathFlowValue';
|
|
9
|
+
mathText: 'mathText';
|
|
10
|
+
mathTextData: 'mathTextData';
|
|
11
|
+
mathTextPadding: 'mathTextPadding';
|
|
12
|
+
mathTextSequence: 'mathTextSequence';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export interface MathSyntaxOptions {
|
|
16
|
+
/** Whether `$x$` (one dollar) is text math. Default `true`. */
|
|
17
|
+
singleDollarTextMath?: boolean | null | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** micromark extension for math syntax. */
|
|
20
|
+
export declare function mathSyntax(options?: MathSyntaxOptions | null): Extension;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Math syntax for micromark (`$$` flow math and `$` text math), ported to TypeScript from
|
|
3
|
+
* micromark-extension-math 3.1.0 (`lib/syntax.js`, `lib/math-flow.js`, `lib/math-text.js`).
|
|
4
|
+
* Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>, MIT; full notice in THIRD-PARTY-NOTICES.md.
|
|
5
|
+
* https://github.com/micromark/micromark-extension-math
|
|
6
|
+
*
|
|
7
|
+
* Why it lives here: micromark-extension-math (and remark-math, which depends on it) declares
|
|
8
|
+
* `katex ^0.16.0` for its HTML compiler, which MarkupMe never uses. npm ignores our root
|
|
9
|
+
* `overrides` for installed packages, so depending on it gave every consumer a vulnerable
|
|
10
|
+
* KaTeX (GHSA-238p-pmpm-9mq7, MKP-7). Only the tokenizers are ported; behaviour is unchanged.
|
|
11
|
+
*/
|
|
12
|
+
import { factorySpace } from 'micromark-factory-space';
|
|
13
|
+
import { markdownLineEnding } from 'micromark-util-character';
|
|
14
|
+
const DOLLAR = 36;
|
|
15
|
+
const SPACE = 32;
|
|
16
|
+
/** micromark extension for math syntax. */
|
|
17
|
+
export function mathSyntax(options) {
|
|
18
|
+
return {
|
|
19
|
+
flow: { [DOLLAR]: mathFlow },
|
|
20
|
+
text: { [DOLLAR]: mathText(options) },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------------------------
|
|
24
|
+
// Flow math: $$ … $$
|
|
25
|
+
const mathFlow = {
|
|
26
|
+
tokenize: tokenizeMathFenced,
|
|
27
|
+
concrete: true,
|
|
28
|
+
name: 'mathFlow',
|
|
29
|
+
};
|
|
30
|
+
const nonLazyContinuation = {
|
|
31
|
+
tokenize: tokenizeNonLazyContinuation,
|
|
32
|
+
partial: true,
|
|
33
|
+
};
|
|
34
|
+
function tokenizeMathFenced(effects, ok, nok) {
|
|
35
|
+
const self = this;
|
|
36
|
+
const tail = self.events[self.events.length - 1];
|
|
37
|
+
const initialSize = tail && tail[1].type === 'linePrefix' ? tail[2].sliceSerialize(tail[1], true).length : 0;
|
|
38
|
+
let sizeOpen = 0;
|
|
39
|
+
return start;
|
|
40
|
+
function start(code) {
|
|
41
|
+
effects.enter('mathFlow');
|
|
42
|
+
effects.enter('mathFlowFence');
|
|
43
|
+
effects.enter('mathFlowFenceSequence');
|
|
44
|
+
return sequenceOpen(code);
|
|
45
|
+
}
|
|
46
|
+
function sequenceOpen(code) {
|
|
47
|
+
if (code === DOLLAR) {
|
|
48
|
+
effects.consume(code);
|
|
49
|
+
sizeOpen++;
|
|
50
|
+
return sequenceOpen;
|
|
51
|
+
}
|
|
52
|
+
if (sizeOpen < 2)
|
|
53
|
+
return nok(code);
|
|
54
|
+
effects.exit('mathFlowFenceSequence');
|
|
55
|
+
return factorySpace(effects, metaBefore, 'whitespace')(code);
|
|
56
|
+
}
|
|
57
|
+
function metaBefore(code) {
|
|
58
|
+
if (code === null || markdownLineEnding(code))
|
|
59
|
+
return metaAfter(code);
|
|
60
|
+
effects.enter('mathFlowFenceMeta');
|
|
61
|
+
effects.enter('chunkString', { contentType: 'string' });
|
|
62
|
+
return meta(code);
|
|
63
|
+
}
|
|
64
|
+
function meta(code) {
|
|
65
|
+
if (code === null || markdownLineEnding(code)) {
|
|
66
|
+
effects.exit('chunkString');
|
|
67
|
+
effects.exit('mathFlowFenceMeta');
|
|
68
|
+
return metaAfter(code);
|
|
69
|
+
}
|
|
70
|
+
if (code === DOLLAR)
|
|
71
|
+
return nok(code);
|
|
72
|
+
effects.consume(code);
|
|
73
|
+
return meta;
|
|
74
|
+
}
|
|
75
|
+
function metaAfter(code) {
|
|
76
|
+
effects.exit('mathFlowFence');
|
|
77
|
+
if (self.interrupt)
|
|
78
|
+
return ok(code);
|
|
79
|
+
return effects.attempt(nonLazyContinuation, beforeNonLazyContinuation, after)(code);
|
|
80
|
+
}
|
|
81
|
+
function beforeNonLazyContinuation(code) {
|
|
82
|
+
return effects.attempt({ tokenize: tokenizeClosingFence, partial: true }, after, contentStart)(code);
|
|
83
|
+
}
|
|
84
|
+
function contentStart(code) {
|
|
85
|
+
return (initialSize
|
|
86
|
+
? factorySpace(effects, beforeContentChunk, 'linePrefix', initialSize + 1)
|
|
87
|
+
: beforeContentChunk)(code);
|
|
88
|
+
}
|
|
89
|
+
function beforeContentChunk(code) {
|
|
90
|
+
if (code === null)
|
|
91
|
+
return after(code);
|
|
92
|
+
if (markdownLineEnding(code)) {
|
|
93
|
+
return effects.attempt(nonLazyContinuation, beforeNonLazyContinuation, after)(code);
|
|
94
|
+
}
|
|
95
|
+
effects.enter('mathFlowValue');
|
|
96
|
+
return contentChunk(code);
|
|
97
|
+
}
|
|
98
|
+
function contentChunk(code) {
|
|
99
|
+
if (code === null || markdownLineEnding(code)) {
|
|
100
|
+
effects.exit('mathFlowValue');
|
|
101
|
+
return beforeContentChunk(code);
|
|
102
|
+
}
|
|
103
|
+
effects.consume(code);
|
|
104
|
+
return contentChunk;
|
|
105
|
+
}
|
|
106
|
+
function after(code) {
|
|
107
|
+
effects.exit('mathFlow');
|
|
108
|
+
return ok(code);
|
|
109
|
+
}
|
|
110
|
+
function tokenizeClosingFence(effects, ok, nok) {
|
|
111
|
+
let size = 0;
|
|
112
|
+
return factorySpace(effects, beforeSequenceClose, 'linePrefix', self.parser.constructs.disable.null?.includes('codeIndented') ? undefined : 4);
|
|
113
|
+
function beforeSequenceClose(code) {
|
|
114
|
+
effects.enter('mathFlowFence');
|
|
115
|
+
effects.enter('mathFlowFenceSequence');
|
|
116
|
+
return sequenceClose(code);
|
|
117
|
+
}
|
|
118
|
+
function sequenceClose(code) {
|
|
119
|
+
if (code === DOLLAR) {
|
|
120
|
+
size++;
|
|
121
|
+
effects.consume(code);
|
|
122
|
+
return sequenceClose;
|
|
123
|
+
}
|
|
124
|
+
if (size < sizeOpen)
|
|
125
|
+
return nok(code);
|
|
126
|
+
effects.exit('mathFlowFenceSequence');
|
|
127
|
+
return factorySpace(effects, afterSequenceClose, 'whitespace')(code);
|
|
128
|
+
}
|
|
129
|
+
function afterSequenceClose(code) {
|
|
130
|
+
if (code === null || markdownLineEnding(code)) {
|
|
131
|
+
effects.exit('mathFlowFence');
|
|
132
|
+
return ok(code);
|
|
133
|
+
}
|
|
134
|
+
return nok(code);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function tokenizeNonLazyContinuation(effects, ok, nok) {
|
|
139
|
+
const self = this;
|
|
140
|
+
return start;
|
|
141
|
+
function start(code) {
|
|
142
|
+
if (code === null)
|
|
143
|
+
return ok(code);
|
|
144
|
+
effects.enter('lineEnding');
|
|
145
|
+
effects.consume(code);
|
|
146
|
+
effects.exit('lineEnding');
|
|
147
|
+
return lineStart;
|
|
148
|
+
}
|
|
149
|
+
function lineStart(code) {
|
|
150
|
+
return self.parser.lazy[self.now().line] ? nok(code) : ok(code);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------------------------------
|
|
154
|
+
// Text math: $ … $ and $$ … $$ inline
|
|
155
|
+
function mathText(options) {
|
|
156
|
+
let single = options?.singleDollarTextMath;
|
|
157
|
+
if (single === null || single === undefined)
|
|
158
|
+
single = true;
|
|
159
|
+
return {
|
|
160
|
+
tokenize: tokenizeMathText,
|
|
161
|
+
resolve: resolveMathText,
|
|
162
|
+
previous,
|
|
163
|
+
name: 'mathText',
|
|
164
|
+
};
|
|
165
|
+
function tokenizeMathText(effects, ok, nok) {
|
|
166
|
+
let sizeOpen = 0;
|
|
167
|
+
let size = 0;
|
|
168
|
+
let token;
|
|
169
|
+
return start;
|
|
170
|
+
function start(code) {
|
|
171
|
+
effects.enter('mathText');
|
|
172
|
+
effects.enter('mathTextSequence');
|
|
173
|
+
return sequenceOpen(code);
|
|
174
|
+
}
|
|
175
|
+
function sequenceOpen(code) {
|
|
176
|
+
if (code === DOLLAR) {
|
|
177
|
+
effects.consume(code);
|
|
178
|
+
sizeOpen++;
|
|
179
|
+
return sequenceOpen;
|
|
180
|
+
}
|
|
181
|
+
if (sizeOpen < 2 && !single)
|
|
182
|
+
return nok(code);
|
|
183
|
+
effects.exit('mathTextSequence');
|
|
184
|
+
return between(code);
|
|
185
|
+
}
|
|
186
|
+
function between(code) {
|
|
187
|
+
if (code === null)
|
|
188
|
+
return nok(code);
|
|
189
|
+
if (code === DOLLAR) {
|
|
190
|
+
token = effects.enter('mathTextSequence');
|
|
191
|
+
size = 0;
|
|
192
|
+
return sequenceClose(code);
|
|
193
|
+
}
|
|
194
|
+
if (code === SPACE) {
|
|
195
|
+
effects.enter('space');
|
|
196
|
+
effects.consume(code);
|
|
197
|
+
effects.exit('space');
|
|
198
|
+
return between;
|
|
199
|
+
}
|
|
200
|
+
if (markdownLineEnding(code)) {
|
|
201
|
+
effects.enter('lineEnding');
|
|
202
|
+
effects.consume(code);
|
|
203
|
+
effects.exit('lineEnding');
|
|
204
|
+
return between;
|
|
205
|
+
}
|
|
206
|
+
effects.enter('mathTextData');
|
|
207
|
+
return data(code);
|
|
208
|
+
}
|
|
209
|
+
function data(code) {
|
|
210
|
+
if (code === null || code === SPACE || code === DOLLAR || markdownLineEnding(code)) {
|
|
211
|
+
effects.exit('mathTextData');
|
|
212
|
+
return between(code);
|
|
213
|
+
}
|
|
214
|
+
effects.consume(code);
|
|
215
|
+
return data;
|
|
216
|
+
}
|
|
217
|
+
function sequenceClose(code) {
|
|
218
|
+
if (code === DOLLAR) {
|
|
219
|
+
effects.consume(code);
|
|
220
|
+
size++;
|
|
221
|
+
return sequenceClose;
|
|
222
|
+
}
|
|
223
|
+
if (size === sizeOpen) {
|
|
224
|
+
effects.exit('mathTextSequence');
|
|
225
|
+
effects.exit('mathText');
|
|
226
|
+
return ok(code);
|
|
227
|
+
}
|
|
228
|
+
// More or fewer dollars than the opening sequence: it is data.
|
|
229
|
+
if (token)
|
|
230
|
+
token.type = 'mathTextData';
|
|
231
|
+
return data(code);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const resolveMathText = (events) => {
|
|
236
|
+
let tailExitIndex = events.length - 4;
|
|
237
|
+
let headEnterIndex = 3;
|
|
238
|
+
let index;
|
|
239
|
+
let enter;
|
|
240
|
+
const at = (i) => events[i][1];
|
|
241
|
+
// A space or line ending on both sides of data is padding.
|
|
242
|
+
if ((at(headEnterIndex).type === 'lineEnding' || at(headEnterIndex).type === 'space') &&
|
|
243
|
+
(at(tailExitIndex).type === 'lineEnding' || at(tailExitIndex).type === 'space')) {
|
|
244
|
+
index = headEnterIndex;
|
|
245
|
+
while (++index < tailExitIndex) {
|
|
246
|
+
if (at(index).type === 'mathTextData') {
|
|
247
|
+
at(tailExitIndex).type = 'mathTextPadding';
|
|
248
|
+
at(headEnterIndex).type = 'mathTextPadding';
|
|
249
|
+
headEnterIndex += 2;
|
|
250
|
+
tailExitIndex -= 2;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Merge adjacent spaces and data.
|
|
256
|
+
index = headEnterIndex - 1;
|
|
257
|
+
tailExitIndex++;
|
|
258
|
+
while (++index <= tailExitIndex) {
|
|
259
|
+
if (enter === undefined) {
|
|
260
|
+
if (index !== tailExitIndex && at(index).type !== 'lineEnding')
|
|
261
|
+
enter = index;
|
|
262
|
+
}
|
|
263
|
+
else if (index === tailExitIndex || at(index).type === 'lineEnding') {
|
|
264
|
+
at(enter).type = 'mathTextData';
|
|
265
|
+
if (index !== enter + 2) {
|
|
266
|
+
at(enter).end = at(index - 1).end;
|
|
267
|
+
events.splice(enter + 2, index - enter - 2);
|
|
268
|
+
tailExitIndex -= index - enter - 2;
|
|
269
|
+
index = enter + 2;
|
|
270
|
+
}
|
|
271
|
+
enter = undefined;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return events;
|
|
275
|
+
};
|
|
276
|
+
const previous = function (code) {
|
|
277
|
+
// If there is a previous code, there will always be a tail.
|
|
278
|
+
return (code !== DOLLAR || this.events[this.events.length - 1][1].type === 'characterEscape');
|
|
279
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remark plugin for math syntax: the in-tree equivalent of remark-math 6.0.0 (MIT,
|
|
3
|
+
* https://github.com/remarkjs/remark-math), using `mdast-util-math` and the ported tokenizers in
|
|
4
|
+
* `math-syntax.ts`. See that file for why remark-math is no longer a dependency (MKP-7).
|
|
5
|
+
* Copyright (c) Junyoung Choi <fluke8259@gmail.com>, MIT; full notice in THIRD-PARTY-NOTICES.md.
|
|
6
|
+
*/
|
|
7
|
+
import { mathFromMarkdown, mathToMarkdown } from 'mdast-util-math';
|
|
8
|
+
import { mathSyntax } from './math-syntax.js';
|
|
9
|
+
export function remarkMath() {
|
|
10
|
+
const data = this.data();
|
|
11
|
+
data.micromarkExtensions ??= [];
|
|
12
|
+
data.fromMarkdownExtensions ??= [];
|
|
13
|
+
data.toMarkdownExtensions ??= [];
|
|
14
|
+
data.micromarkExtensions.push(mathSyntax());
|
|
15
|
+
data.fromMarkdownExtensions.push(mathFromMarkdown());
|
|
16
|
+
data.toMarkdownExtensions.push(mathToMarkdown());
|
|
17
|
+
}
|
package/dist/render/html.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import rehypeKatex from 'rehype-katex';
|
|
2
1
|
import rehypeRaw from 'rehype-raw';
|
|
3
2
|
import rehypeSanitize from 'rehype-sanitize';
|
|
4
3
|
import rehypeStringify from 'rehype-stringify';
|
|
@@ -8,6 +7,7 @@ import { visit } from 'unist-util-visit';
|
|
|
8
7
|
import { presentAlerts } from '../plugins/alerts.js';
|
|
9
8
|
import { presentDirectives } from '../plugins/directives.js';
|
|
10
9
|
import { presentEmoji } from '../plugins/emoji.js';
|
|
10
|
+
import { rehypeKatex } from './katex.js';
|
|
11
11
|
import { markupmeSchema } from './schema.js';
|
|
12
12
|
const CLOBBER = 'user-content-';
|
|
13
13
|
function textOf(node) {
|
|
@@ -196,9 +196,7 @@ export async function renderHtml(doc, opts, r, diagnostics) {
|
|
|
196
196
|
}
|
|
197
197
|
});
|
|
198
198
|
if (opts.math === true)
|
|
199
|
-
out = (await unified()
|
|
200
|
-
.use(rehypeKatex, { throwOnError: false })
|
|
201
|
-
.run(out));
|
|
199
|
+
out = (await unified().use(rehypeKatex).run(out));
|
|
202
200
|
// Fill slots with trusted HTML.
|
|
203
201
|
visit(out, 'element', (el, i, parent) => {
|
|
204
202
|
const id = el.properties.id;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rehype plugin that renders math with KaTeX: the in-tree equivalent of rehype-katex 7.0.1 (MIT,
|
|
3
|
+
* https://github.com/remarkjs/remark-math), calling the `katex` version this package pins.
|
|
4
|
+
* Copyright (c) Junyoung Choi <fluke8259@gmail.com>, MIT; full notice in THIRD-PARTY-NOTICES.md.
|
|
5
|
+
* rehype-katex declares `katex ^0.16.0`, and npm ignores our root `overrides` for installed
|
|
6
|
+
* packages, so depending on it gave every consumer a vulnerable KaTeX (GHSA-238p-pmpm-9mq7,
|
|
7
|
+
* MKP-7). Behaviour is unchanged: elements with a `language-math`, `math-display` or
|
|
8
|
+
* `math-inline` class are replaced by KaTeX output; errors are reported on the file and
|
|
9
|
+
* rendered in KaTeX's error style.
|
|
10
|
+
*/
|
|
11
|
+
import type { Root } from 'hast';
|
|
12
|
+
import type { VFile } from 'vfile';
|
|
13
|
+
export declare function rehypeKatex(): (tree: Root, file: VFile) => undefined;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { fromHtmlIsomorphic } from 'hast-util-from-html-isomorphic';
|
|
2
|
+
import { toText } from 'hast-util-to-text';
|
|
3
|
+
import katex from 'katex';
|
|
4
|
+
import { SKIP, visitParents } from 'unist-util-visit-parents';
|
|
5
|
+
export function rehypeKatex() {
|
|
6
|
+
return (tree, file) => {
|
|
7
|
+
visitParents(tree, 'element', (element, parents) => {
|
|
8
|
+
const classes = Array.isArray(element.properties.className)
|
|
9
|
+
? element.properties.className
|
|
10
|
+
: [];
|
|
11
|
+
// ```math fenced code
|
|
12
|
+
const languageMath = classes.includes('language-math');
|
|
13
|
+
// $$ flow math
|
|
14
|
+
const mathDisplay = classes.includes('math-display');
|
|
15
|
+
// $ text math
|
|
16
|
+
const mathInline = classes.includes('math-inline');
|
|
17
|
+
let displayMode = mathDisplay;
|
|
18
|
+
if (!languageMath && !mathDisplay && !mathInline)
|
|
19
|
+
return;
|
|
20
|
+
let parent = parents[parents.length - 1];
|
|
21
|
+
let scope = element;
|
|
22
|
+
// ```math: replace the <pre> and use display mode.
|
|
23
|
+
if (element.tagName === 'code' &&
|
|
24
|
+
languageMath &&
|
|
25
|
+
parent &&
|
|
26
|
+
parent.type === 'element' &&
|
|
27
|
+
parent.tagName === 'pre') {
|
|
28
|
+
scope = parent;
|
|
29
|
+
parent = parents[parents.length - 2];
|
|
30
|
+
displayMode = true;
|
|
31
|
+
}
|
|
32
|
+
if (!parent)
|
|
33
|
+
return;
|
|
34
|
+
const value = toText(scope, { whitespace: 'pre' });
|
|
35
|
+
let result;
|
|
36
|
+
try {
|
|
37
|
+
result = katex.renderToString(value, { displayMode, throwOnError: true });
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const cause = error;
|
|
41
|
+
file.message('Could not render math with KaTeX', {
|
|
42
|
+
ancestors: [...parents, element],
|
|
43
|
+
cause,
|
|
44
|
+
place: element.position,
|
|
45
|
+
ruleId: cause.name.toLowerCase(),
|
|
46
|
+
source: 'rehype-katex',
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
result = katex.renderToString(value, {
|
|
50
|
+
displayMode,
|
|
51
|
+
strict: 'ignore',
|
|
52
|
+
throwOnError: false,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// KaTeX's error markup, for errors it does not handle itself.
|
|
57
|
+
result = [
|
|
58
|
+
{
|
|
59
|
+
type: 'element',
|
|
60
|
+
tagName: 'span',
|
|
61
|
+
properties: {
|
|
62
|
+
className: ['katex-error'],
|
|
63
|
+
style: 'color:#cc0000',
|
|
64
|
+
title: String(error),
|
|
65
|
+
},
|
|
66
|
+
children: [{ type: 'text', value }],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (typeof result === 'string') {
|
|
72
|
+
result = fromHtmlIsomorphic(result, { fragment: true }).children;
|
|
73
|
+
}
|
|
74
|
+
const index = parent.children.indexOf(scope);
|
|
75
|
+
parent.children.splice(index, 1, ...result);
|
|
76
|
+
return SKIP;
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.1.
|
|
1
|
+
export const VERSION = '0.1.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markupme/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "MarkupMe core: standards-first Markdown (CommonMark + GFM) parsing, a typed document model, safe HTML rendering, Markdown serialization, linting and TOC on unified/remark.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Yarlis AI Solutions",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"dist",
|
|
37
|
+
"THIRD-PARTY-NOTICES.md",
|
|
37
38
|
"!dist/**/*.tsbuildinfo"
|
|
38
39
|
],
|
|
39
40
|
"publishConfig": {
|
|
@@ -51,23 +52,30 @@
|
|
|
51
52
|
"@types/unist": "3.0.3",
|
|
52
53
|
"gemoji": "8.1.0",
|
|
53
54
|
"github-slugger": "2.0.0",
|
|
55
|
+
"hast-util-from-html-isomorphic": "2.0.0",
|
|
54
56
|
"hast-util-sanitize": "5.0.2",
|
|
57
|
+
"hast-util-to-text": "4.0.2",
|
|
58
|
+
"katex": "0.19.1",
|
|
55
59
|
"mdast-util-directive": "3.2.0",
|
|
60
|
+
"mdast-util-math": "3.0.0",
|
|
56
61
|
"mdast-util-to-string": "4.0.0",
|
|
57
|
-
"
|
|
62
|
+
"micromark-factory-space": "2.1.0",
|
|
63
|
+
"micromark-util-character": "2.1.1",
|
|
64
|
+
"micromark-util-types": "2.0.3",
|
|
58
65
|
"rehype-raw": "7.0.0",
|
|
59
66
|
"rehype-sanitize": "6.0.0",
|
|
60
67
|
"rehype-stringify": "10.0.1",
|
|
61
68
|
"remark-directive": "4.0.0",
|
|
62
69
|
"remark-frontmatter": "5.0.0",
|
|
63
70
|
"remark-gfm": "4.0.1",
|
|
64
|
-
"remark-math": "6.0.0",
|
|
65
71
|
"remark-parse": "11.0.0",
|
|
66
72
|
"remark-rehype": "11.1.2",
|
|
67
73
|
"remark-stringify": "11.0.0",
|
|
68
74
|
"smol-toml": "1.9.1",
|
|
69
75
|
"unified": "11.0.5",
|
|
70
76
|
"unist-util-visit": "5.2.0",
|
|
77
|
+
"unist-util-visit-parents": "6.0.2",
|
|
78
|
+
"vfile": "6.0.3",
|
|
71
79
|
"yaml": "2.9.1"
|
|
72
80
|
},
|
|
73
81
|
"engines": {
|