rapier-html 1.2.52 → 1.2.55
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/BUILD.json +4 -4
- package/README.md +0 -5
- package/dist/ledger/math/delimiters.mjs +56 -17
- package/dist/ledger/math/markdown-rules.mjs +22 -6
- package/dist/ledger/md-assets.mjs +39 -80
- package/dist/ledger/md-engine.mjs +650 -26
- package/dist/ledger/md-marks.mjs +15 -12
- package/dist/ledger/md-parser-config.mjs +175 -25
- package/dist/rapier.html +72 -64
- package/package.json +1 -1
package/dist/ledger/md-marks.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {markdownSourcePositions} from "./md-source.mjs";
|
|
3
3
|
|
|
4
4
|
export function fontDataUrl(url) {
|
|
5
|
-
if (typeof url !== 'string') return null;
|
|
5
|
+
if (typeof url !== 'string' || url.length < 28 || (url.charCodeAt(0) | 32) !== 0x64 || url.charCodeAt(4) !== 0x3a) return null;
|
|
6
6
|
const match = /^data:font\/(woff2|woff|ttf|otf);base64,([A-Za-z0-9+/]+={0,2})$/i.exec(url);
|
|
7
7
|
if (!match || match[2].length % 4) return null;
|
|
8
8
|
const padding = match[2].endsWith('==') ? 2 : match[2].endsWith('=') ? 1 : 0;
|
|
@@ -25,6 +25,8 @@ const inkReader = () => {
|
|
|
25
25
|
const INK_OPEN_BODY = '(' + INK_KINDS.join('|') + ')(?: ([1-9]\\d{0,5}))?(?: (' + COLOR_VALUE + '))?(?: w=([1-9]\\d?))?(?: box=(\\d{1,6}),(\\d{1,6}))?(?: at=(' + INK_INT + '),(' + INK_INT + '))?'
|
|
26
26
|
+ '(?: (' + INK_INT + ',' + INK_INT + '(?: ' + INK_INT + ',' + INK_INT + ')*))?';
|
|
27
27
|
const INK_OPEN_PATTERN = '<!--ink ' + INK_OPEN_BODY + '-->';
|
|
28
|
+
const INK_OPEN_EXACT_RE = new RegExp('^' + INK_OPEN_PATTERN + '$');
|
|
29
|
+
const INK_OPEN_PREFIX_RE = new RegExp('^' + INK_OPEN_PATTERN);
|
|
28
30
|
|
|
29
31
|
function readInkMatch(match) {
|
|
30
32
|
const linked = match[1] === 'arrow' || match[1] === 'end';
|
|
@@ -53,17 +55,17 @@ const inkReader = () => {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
function parseInkOpen(comment) {
|
|
56
|
-
if (typeof comment !== 'string') return null;
|
|
57
|
-
const match =
|
|
58
|
+
if (typeof comment !== 'string' || !comment.startsWith('<!--ink ')) return null;
|
|
59
|
+
const match = INK_OPEN_EXACT_RE.exec(comment);
|
|
58
60
|
return match && readInkMatch(match);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
function parseInkBody(body) {
|
|
62
64
|
return typeof body === 'string' ? parseInkOpen('<!--ink ' + body + '-->') : null;
|
|
63
65
|
}
|
|
64
|
-
return { TEXT_COLOR_NAMES, COLOR_NAME_ALT, COLOR_VALUE, INK_KINDS, INK_PATH_MAX, INK_INT_MAX, INK_OPEN_PATTERN, readInkMatch, parseInkOpen, parseInkBody };
|
|
66
|
+
return { TEXT_COLOR_NAMES, COLOR_NAME_ALT, COLOR_VALUE, INK_KINDS, INK_PATH_MAX, INK_INT_MAX, INK_OPEN_PATTERN, INK_OPEN_EXACT_RE, INK_OPEN_PREFIX_RE, readInkMatch, parseInkOpen, parseInkBody };
|
|
65
67
|
};
|
|
66
|
-
const { TEXT_COLOR_NAMES, COLOR_VALUE, INK_KINDS, INK_PATH_MAX, INK_INT_MAX, INK_OPEN_PATTERN, readInkMatch, parseInkOpen, parseInkBody } = inkReader();
|
|
68
|
+
const { TEXT_COLOR_NAMES, COLOR_VALUE, INK_KINDS, INK_PATH_MAX, INK_INT_MAX, INK_OPEN_PATTERN, INK_OPEN_EXACT_RE, INK_OPEN_PREFIX_RE, readInkMatch, parseInkOpen, parseInkBody } = inkReader();
|
|
67
69
|
export { readInkMatch, parseInkOpen, parseInkBody };
|
|
68
70
|
|
|
69
71
|
const TEXT_COLOR_HEX_TO_NAME = Object.freeze(
|
|
@@ -262,7 +264,7 @@ export function createTypography({normalizeFontFamily, fontFamilyCss, FONT_STACK
|
|
|
262
264
|
md.core.ruler.after('linkify', 'rapier-typography', state => {
|
|
263
265
|
for (let at = 0; at < state.tokens.length; at++) {
|
|
264
266
|
const block = state.tokens[at];
|
|
265
|
-
if (block.type !== 'inline' || !block.children || block.content.indexOf('<') < 0) continue;
|
|
267
|
+
if (block.type !== 'inline' || !block.children || block.content.indexOf('<') < 0 || !/<span/i.test(block.content)) continue;
|
|
266
268
|
const stack = []; let depth = 0, overflow = 0;
|
|
267
269
|
for (const token of block.children) {
|
|
268
270
|
if (token.type !== 'html_inline') { depth += token.nesting || 0; continue; }
|
|
@@ -297,7 +299,8 @@ export const typography = createTypography({normalizeFontFamily, fontFamilyCss,
|
|
|
297
299
|
export function typographySourceRanges(source, parser) { return markdownSourcePositions(source, parser).typography; }
|
|
298
300
|
|
|
299
301
|
const INK_CLOSE = '<!--/ink-->';
|
|
300
|
-
|
|
302
|
+
const INK_OPEN_PREFIX = '<!--ink ';
|
|
303
|
+
export { INK_KINDS, INK_CLOSE, INK_PATH_MAX, INK_INT_MAX, INK_OPEN_PATTERN, INK_OPEN_PREFIX };
|
|
301
304
|
|
|
302
305
|
const inkInt = (value, name) => {
|
|
303
306
|
if (!Number.isInteger(value) || Math.abs(value) > INK_INT_MAX) throw new TypeError('ink: ' + name + ' must be an integer within ' + INK_INT_MAX);
|
|
@@ -344,16 +347,16 @@ export function formatInkRun(mark, content) {
|
|
|
344
347
|
}
|
|
345
348
|
|
|
346
349
|
export function matchInkOpen(text) {
|
|
347
|
-
if (typeof text !== 'string') return null;
|
|
348
|
-
const match =
|
|
350
|
+
if (typeof text !== 'string' || !text.startsWith('<!--ink ')) return null;
|
|
351
|
+
const match = INK_OPEN_PREFIX_RE.exec(text);
|
|
349
352
|
if (!match) return null;
|
|
350
353
|
const mark = readInkMatch(match);
|
|
351
354
|
return mark && { mark, length: match[0].length };
|
|
352
355
|
}
|
|
353
356
|
|
|
354
357
|
export function inkOpenBody(opener) {
|
|
355
|
-
if (typeof opener !== 'string') return null;
|
|
356
|
-
const match =
|
|
358
|
+
if (typeof opener !== 'string' || !opener.startsWith('<!--ink ')) return null;
|
|
359
|
+
const match = INK_OPEN_EXACT_RE.exec(opener);
|
|
357
360
|
return match && readInkMatch(match) ? opener.slice(8, -3) : null;
|
|
358
361
|
}
|
|
359
362
|
export function formatInkOpenFromBody(body) {
|
|
@@ -736,5 +739,5 @@ export function isPageBreakLine(text) {
|
|
|
736
739
|
}
|
|
737
740
|
|
|
738
741
|
export function isPageBreakBlock(text) {
|
|
739
|
-
return typeof text === 'string' &&
|
|
742
|
+
return typeof text === 'string' && text.startsWith(PAGE_BREAK_MARKER) && (text.length === 23 || (text.length === 24 && (text.charCodeAt(23) === 0x0a || text.charCodeAt(23) === 0x0d)) || (text.length === 25 && text.charCodeAt(23) === 0x0d && text.charCodeAt(24) === 0x0a));
|
|
740
743
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2026 Jack Skipworth. See LICENSE-MIT.
|
|
3
3
|
// Feather callout paths retain the copyright and MIT notice in agent/vendor/NOTICE.txt.
|
|
4
4
|
import {tuneMarkdownEngine} from "./md-engine.mjs";
|
|
5
|
-
import {fontDataUrl as rapierFontDataUrl} from "./md-marks.mjs";
|
|
5
|
+
import {fontDataUrl as rapierFontDataUrl, INK_OPEN_PREFIX, PAGE_BREAK_MARKER} from "./md-marks.mjs";
|
|
6
6
|
import {typography as rapierTypography, matchInkOpen as rapierMatchInkOpen, isInkClose as rapierIsInkClose,
|
|
7
7
|
inkOpenBody as rapierInkOpenBody, parseInkOpen as rapierParseInkOpen, isPageBreakBlock as rapierIsPageBreakBlock} from "./md-marks.mjs";
|
|
8
8
|
import {installMathRules} from "./math/markdown-rules.mjs";
|
|
@@ -39,19 +39,66 @@ const RAPIER_MARKDOWN_SPEC = Object.freeze({
|
|
|
39
39
|
rules: Object.freeze({ mathBlock: 'temml_math_block' }),
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
const _rapierLinkifyCandidate = {names: null,
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
const names =
|
|
42
|
+
const _rapierLinkifyCandidate = {names: null, schemaRe: null, tldsRef: null, tldSet: null, maxTld: 6};
|
|
43
|
+
function _rapierLinkFlags(text, linkify) {
|
|
44
|
+
const len = text.length;
|
|
45
|
+
if (len < 4) return 0;
|
|
46
|
+
const names = linkify.re.get_schema_names();
|
|
47
47
|
if (_rapierLinkifyCandidate.names !== names) {
|
|
48
48
|
_rapierLinkifyCandidate.names = names;
|
|
49
|
-
_rapierLinkifyCandidate.
|
|
49
|
+
_rapierLinkifyCandidate.schemaRe = new RegExp(names.source, 'i');
|
|
50
|
+
}
|
|
51
|
+
let flags = 0;
|
|
52
|
+
if (text.indexOf(':') >= 0 || text.indexOf('/') >= 0 || text.indexOf('w') >= 0 || text.indexOf('W') >= 0) {
|
|
53
|
+
if (_rapierLinkifyCandidate.schemaRe.test(text)) flags |= 1;
|
|
50
54
|
}
|
|
51
|
-
const
|
|
55
|
+
const dotFirst = text.indexOf('.');
|
|
56
|
+
if (dotFirst < 0) return flags;
|
|
57
|
+
const atPos = text.indexOf('@');
|
|
58
|
+
if (atPos > 0 && text.indexOf('.', atPos + 2) > 0) flags |= 4;
|
|
59
|
+
if (!linkify.__opts__.fuzzyLink) return flags;
|
|
60
|
+
if (linkify.__opts__.fuzzyIP && /\d\.\d/.test(text)) return flags | 2;
|
|
61
|
+
const tlds = linkify.__opts__.tlds;
|
|
62
|
+
if (_rapierLinkifyCandidate.tldsRef !== tlds) {
|
|
63
|
+
_rapierLinkifyCandidate.tldsRef = tlds;
|
|
64
|
+
const set = new Set();
|
|
65
|
+
let max = 2;
|
|
66
|
+
for (let i = 0; i < tlds.length; i++) {
|
|
67
|
+
const t = tlds[i].toLowerCase();
|
|
68
|
+
set.add(t);
|
|
69
|
+
if (t.length > max) max = t.length;
|
|
70
|
+
}
|
|
71
|
+
_rapierLinkifyCandidate.tldSet = set;
|
|
72
|
+
_rapierLinkifyCandidate.maxTld = max;
|
|
73
|
+
}
|
|
74
|
+
const tldSet = _rapierLinkifyCandidate.tldSet, maxTld = _rapierLinkifyCandidate.maxTld;
|
|
75
|
+
for (let dot = dotFirst; dot !== -1 && dot + 2 < len; dot = text.indexOf('.', dot + 1)) {
|
|
76
|
+
if (dot === 0) continue;
|
|
77
|
+
const c1 = text.charCodeAt(dot + 1) | 32;
|
|
78
|
+
if (!((c1 >= 0x61 && c1 <= 0x7a) || c1 > 127)) continue;
|
|
79
|
+
if (c1 === 0x78 && (text.charCodeAt(dot + 2) | 32) === 0x6e && text.charCodeAt(dot + 3) === 0x2d && text.charCodeAt(dot + 4) === 0x2d) return flags | 2;
|
|
80
|
+
let end = dot + 2;
|
|
81
|
+
const limit = Math.min(len, dot + 1 + maxTld + 1);
|
|
82
|
+
while (end < limit) {
|
|
83
|
+
const c = text.charCodeAt(end);
|
|
84
|
+
if ((c >= 0x61 && c <= 0x7a) || (c >= 0x41 && c <= 0x5a) || (c >= 0x30 && c <= 0x39) || c === 0x2d || c > 127) end++;
|
|
85
|
+
else break;
|
|
86
|
+
}
|
|
87
|
+
const labelLen = end - (dot + 1);
|
|
88
|
+
if (labelLen >= 2 && labelLen <= maxTld && tldSet.has(text.slice(dot + 1, end).toLowerCase())) return flags | 2;
|
|
89
|
+
}
|
|
90
|
+
return flags;
|
|
91
|
+
}
|
|
92
|
+
function _rapierMayContainLink(text, linkify) {
|
|
93
|
+
return _rapierLinkFlags(text, linkify) !== 0;
|
|
94
|
+
}
|
|
95
|
+
function _rapierLinkifyText(state) {
|
|
96
|
+
const md = state.md;
|
|
97
|
+
if (!md.options.linkify) return;
|
|
98
|
+
const linkify = md.linkify;
|
|
52
99
|
for (let at = 0; at < state.tokens.length; at++) {
|
|
53
100
|
const block = state.tokens[at];
|
|
54
|
-
if (block.type !== 'inline' || !
|
|
101
|
+
if (block.type !== 'inline' || !_rapierMayContainLink(block.content, linkify)) continue;
|
|
55
102
|
const children = block.children;
|
|
56
103
|
const source = block.content;
|
|
57
104
|
let htmlDepth = 0, wholeSource, changes;
|
|
@@ -66,8 +113,8 @@ function _rapierLinkifyText(state) {
|
|
|
66
113
|
if (/^<a[>\s]/i.test(child.content) && htmlDepth > 0) htmlDepth--;
|
|
67
114
|
if (/^<\/a\s*>/i.test(child.content)) htmlDepth++;
|
|
68
115
|
}
|
|
69
|
-
if (htmlDepth || child.type !== 'text' || !
|
|
70
|
-
let matches =
|
|
116
|
+
if (htmlDepth || child.type !== 'text' || !_rapierMayContainLink(child.content, linkify)) continue;
|
|
117
|
+
let matches = linkify.match(child.content);
|
|
71
118
|
if (!matches?.length) continue;
|
|
72
119
|
wholeSource ??= md.linkify.test(source);
|
|
73
120
|
if (!wholeSource) break;
|
|
@@ -202,16 +249,24 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
202
249
|
{
|
|
203
250
|
const taskLists = instance.core.ruler.__rules__.find(rule => rule.name === 'github-task-lists').fn;
|
|
204
251
|
instance.core.ruler.at('github-task-lists', function rapierTaskLists(state) {
|
|
205
|
-
|
|
252
|
+
if (state.src.indexOf('[') < 0) return;
|
|
253
|
+
const stranded = [];
|
|
254
|
+
let levelMask = 0;
|
|
255
|
+
const levels = new Set();
|
|
206
256
|
for (let at = 0; at < state.tokens.length; at++) {
|
|
207
|
-
const token = state.tokens[at];
|
|
208
|
-
if (token.type === 'list_item_open'
|
|
209
|
-
|
|
257
|
+
const token = state.tokens[at], lv = token.level;
|
|
258
|
+
if (token.type === 'list_item_open') {
|
|
259
|
+
const prev = lv - 1;
|
|
260
|
+
if (!(prev >= 0 && prev < 31 ? (levelMask & (1 << prev)) : levels.has(prev))) stranded.push(token);
|
|
261
|
+
}
|
|
262
|
+
if (lv >= 0 && lv < 31) levelMask |= (1 << lv);
|
|
263
|
+
else levels.add(lv);
|
|
210
264
|
}
|
|
211
265
|
for (const item of stranded) item.type = '';
|
|
212
266
|
try { taskLists(state); } finally { for (const item of stranded) item.type = 'list_item_open'; }
|
|
213
267
|
});
|
|
214
268
|
instance.core.ruler.after('github-task-lists', 'rapier-empty-task-lists', function rapierEmptyTaskLists(state) {
|
|
269
|
+
if (state.src.indexOf('[') < 0 && state.src.indexOf('"type="checkbox"') < 0) return;
|
|
215
270
|
const tokens = state.tokens || [];
|
|
216
271
|
for (let index = 0; index < tokens.length; index++) {
|
|
217
272
|
const token = tokens[index];
|
|
@@ -305,7 +360,8 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
305
360
|
const originalHtmlBlock = htmlBlockRule.fn;
|
|
306
361
|
const inkAwareHtmlBlock = function rapierInkAwareHtmlBlock(state, startLine, endLine, silent) {
|
|
307
362
|
const start = state.bMarks[startLine] + state.tShift[startLine];
|
|
308
|
-
if (state.src.charCodeAt(start)
|
|
363
|
+
if (state.src.charCodeAt(start) !== 0x3C) return false;
|
|
364
|
+
if (state.src.startsWith(INK_OPEN_PREFIX, start) && rapierMatchInkOpen(state.src.slice(start, start + 2048))) return false;
|
|
309
365
|
return originalHtmlBlock(state, startLine, endLine, silent);
|
|
310
366
|
};
|
|
311
367
|
inkAwareHtmlBlock.rapierInkAware = true;
|
|
@@ -313,9 +369,10 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
313
369
|
}
|
|
314
370
|
rapierTypography.install(instance);
|
|
315
371
|
instance.core.ruler.after('rapier-typography', 'rapier-ink', function rapierInkPairs(state) {
|
|
372
|
+
if (state.src.indexOf(INK_OPEN_PREFIX) < 0) return;
|
|
316
373
|
for (let at = 0; at < state.tokens.length; at++) {
|
|
317
374
|
const blockToken = state.tokens[at];
|
|
318
|
-
if (blockToken.type !== 'inline' || !Array.isArray(blockToken.children) || blockToken.content.indexOf(
|
|
375
|
+
if (blockToken.type !== 'inline' || !Array.isArray(blockToken.children) || blockToken.content.indexOf(INK_OPEN_PREFIX) < 0) continue;
|
|
319
376
|
const children = blockToken.children;
|
|
320
377
|
const stack = [];
|
|
321
378
|
let depth = 0;
|
|
@@ -348,6 +405,7 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
348
405
|
}
|
|
349
406
|
{
|
|
350
407
|
instance.core.ruler.after('block', 'rapier-page-break', function rapierPageBreak(state) {
|
|
408
|
+
if (state.src.indexOf(PAGE_BREAK_MARKER) < 0) return;
|
|
351
409
|
for (let at = 0; at < state.tokens.length; at++) {
|
|
352
410
|
const token = state.tokens[at];
|
|
353
411
|
if (token.type !== 'html_block' || !rapierIsPageBreakBlock(token.content)) continue;
|
|
@@ -411,9 +469,90 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
411
469
|
match.url = www ? 'http://' + raw : raw;
|
|
412
470
|
return match;
|
|
413
471
|
};
|
|
414
|
-
const nativeMatch = linkify.match;
|
|
472
|
+
const nativeMatch = linkify.match, nativeTest = linkify.test;
|
|
473
|
+
let MatchCtor = null;
|
|
474
|
+
linkify.test = function (source) {
|
|
475
|
+
const flags = _rapierLinkFlags(source, this);
|
|
476
|
+
if (!flags) return false;
|
|
477
|
+
return nativeTest.call(this, source);
|
|
478
|
+
};
|
|
415
479
|
linkify.match = function (source) {
|
|
416
|
-
const
|
|
480
|
+
const flags = _rapierLinkFlags(source, this);
|
|
481
|
+
if (!flags) return null;
|
|
482
|
+
if (!MatchCtor) {
|
|
483
|
+
const sample = nativeMatch.call(this, 'http://a.com');
|
|
484
|
+
if (sample?.[0]) MatchCtor = Object.getPrototypeOf(sample[0]).constructor;
|
|
485
|
+
}
|
|
486
|
+
let matches;
|
|
487
|
+
if (!MatchCtor || flags === 7) {
|
|
488
|
+
matches = nativeMatch.call(this, source);
|
|
489
|
+
} else {
|
|
490
|
+
const list = [];
|
|
491
|
+
const r = (flags & 1) ? this.re.get_schema_search() : null;
|
|
492
|
+
const n = (flags & 2) && this.__opts__.fuzzyLink && this.__schemas__['http:'] ? this.re.get_fuzzy_link_search() : null;
|
|
493
|
+
const s = (flags & 4) && this.__opts__.fuzzyEmail && this.__schemas__['mailto:'] ? this.re.get_fuzzy_mail_host_search() : null;
|
|
494
|
+
const o = s ? this.re.get_mail_name_validator() : null;
|
|
495
|
+
if (r) r.lastIndex = 0;
|
|
496
|
+
if (n) n.lastIndex = 0;
|
|
497
|
+
if (s) s.lastIndex = 0;
|
|
498
|
+
let i, a, u, c = !r, l = !n, h = !s, p = 0;
|
|
499
|
+
for (;;) {
|
|
500
|
+
const f = Math.max(p - 1, 0);
|
|
501
|
+
if (s && o && !h && (!a || a.index < p)) {
|
|
502
|
+
if (s.lastIndex < f) s.lastIndex = f;
|
|
503
|
+
for (;;) {
|
|
504
|
+
const t = s.exec(source);
|
|
505
|
+
if (!t) { h = true; a = undefined; break; }
|
|
506
|
+
const m = o.exec(source.slice(Math.max(0, t.index - 65), t.index));
|
|
507
|
+
if (m) {
|
|
508
|
+
a = {schema: 'mailto:', index: t.index - m[1].length, lastIndex: t.index + t[0].length};
|
|
509
|
+
if (a.index >= p) break;
|
|
510
|
+
if (s.lastIndex < f) s.lastIndex = f;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (n && !l && (!i || i.index < p)) {
|
|
515
|
+
if (n.lastIndex < f) n.lastIndex = f;
|
|
516
|
+
for (;;) {
|
|
517
|
+
const t = n.exec(source);
|
|
518
|
+
if (!t) { l = true; i = undefined; break; }
|
|
519
|
+
i = {schema: '', index: t.index + t[1].length, lastIndex: t.index + t[0].length};
|
|
520
|
+
if (i.index >= p) break;
|
|
521
|
+
if (n.lastIndex < f) n.lastIndex = f;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
let d, g = a;
|
|
525
|
+
if (!g || (i && (i.index < g.index || (i.index === g.index && i.lastIndex > g.lastIndex)))) g = i;
|
|
526
|
+
if (!c) {
|
|
527
|
+
for (;;) {
|
|
528
|
+
if (!u) {
|
|
529
|
+
if (r.lastIndex < f) r.lastIndex = f;
|
|
530
|
+
const t = r.exec(source);
|
|
531
|
+
if (!t) { c = true; break; }
|
|
532
|
+
u = {schema: t[2], index: t.index + t[1].length, lastIndex: t.index + t[0].length};
|
|
533
|
+
}
|
|
534
|
+
if (u.index < p) { u = undefined; continue; }
|
|
535
|
+
if (g && u.index > g.index) break;
|
|
536
|
+
const t = u;
|
|
537
|
+
u = undefined;
|
|
538
|
+
const len = this.testSchemaAt(source, t.schema, t.lastIndex);
|
|
539
|
+
if (len) { d = {schema: t.schema, index: t.index, lastIndex: t.lastIndex + len}; break; }
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
let m = d;
|
|
543
|
+
if (!m || (a && (a.index < m.index || (a.index === m.index && a.lastIndex > m.lastIndex)))) m = a;
|
|
544
|
+
if (!m || (i && (i.index < m.index || (i.index === m.index && i.lastIndex > m.lastIndex)))) m = i;
|
|
545
|
+
if (!m) break;
|
|
546
|
+
if (m === a) a = undefined;
|
|
547
|
+
else if (m === i) i = undefined;
|
|
548
|
+
const item = new MatchCtor(source, m.schema, m.index, m.lastIndex);
|
|
549
|
+
if (item.schema) this.__schemas__[item.schema].normalize(item, this);
|
|
550
|
+
else this.normalize(item);
|
|
551
|
+
list.push(item);
|
|
552
|
+
p = m.lastIndex;
|
|
553
|
+
}
|
|
554
|
+
matches = list.length ? list : null;
|
|
555
|
+
}
|
|
417
556
|
if (!matches) return matches;
|
|
418
557
|
const result = [];
|
|
419
558
|
let end = 0;
|
|
@@ -428,18 +567,20 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
428
567
|
linkify.matchAtStart = function (source) { return refineLink(nativeMatchAtStart.call(this, source), source); };
|
|
429
568
|
const inlineLinkify = instance.inline.ruler.__rules__.find(rule => rule.name === 'linkify').fn;
|
|
430
569
|
instance.inline.ruler.at('linkify', function rapierInlineLinkify(state, silent) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
570
|
+
const pos = state.pos, src = state.src;
|
|
571
|
+
if (pos + 3 > state.posMax || src.charCodeAt(pos) !== 0x3a || src.charCodeAt(pos + 1) !== 0x2f || src.charCodeAt(pos + 2) !== 0x2f) return false;
|
|
572
|
+
const prefix = src.slice(Math.max(0, pos - 5), pos).toLowerCase();
|
|
573
|
+
const width = prefix.endsWith('https') ? 5 : prefix.endsWith('http') ? 4 : 0;
|
|
574
|
+
if (width && !allowedStart(src, pos - width)) return false;
|
|
436
575
|
return inlineLinkify(state, silent);
|
|
437
576
|
});
|
|
438
577
|
}
|
|
439
578
|
const disallowedTag = /<\/?(?:title|textarea|style|xmp|iframe|noembed|noframes|script|plaintext)(?=[ \t\n\v\f\r/>])/gi;
|
|
579
|
+
const disallowedTest = /<\/?(?:title|textarea|style|xmp|iframe|noembed|noframes|script|plaintext)(?=[ \t\n\v\f\r/>])/i;
|
|
440
580
|
instance.core.ruler.push('rapier-tagfilter', function rapierTagfilter(state) {
|
|
581
|
+
if (state.src.indexOf('<') < 0 || !disallowedTest.test(state.src)) return;
|
|
441
582
|
const filter = token => {
|
|
442
|
-
if (token.type === 'html_inline' || token.type === 'html_block') {
|
|
583
|
+
if ((token.type === 'html_inline' || token.type === 'html_block') && disallowedTest.test(token.content)) {
|
|
443
584
|
token.content = token.content.replace(disallowedTag, tag => '<' + tag.slice(1));
|
|
444
585
|
}
|
|
445
586
|
};
|
|
@@ -449,6 +590,15 @@ function _rapierApplyMarkdownSpec(instance, root, spec = RAPIER_MARKDOWN_SPEC) {
|
|
|
449
590
|
if (token.type === 'inline' && token.content.indexOf('<') >= 0) for (const child of token.children || []) filter(child);
|
|
450
591
|
}
|
|
451
592
|
});
|
|
593
|
+
const emojiRule = instance.core.ruler.__rules__.find(rule => rule.name === 'emoji');
|
|
594
|
+
if (emojiRule) {
|
|
595
|
+
const origEmoji = emojiRule.fn;
|
|
596
|
+
const emojiQuickRe = /:|<3|<\/3|<\\3|[8BXx][-']?[()]/;
|
|
597
|
+
instance.core.ruler.at('emoji', function rapierEmoji(state) {
|
|
598
|
+
if (!emojiQuickRe.test(state.src)) return;
|
|
599
|
+
origEmoji(state);
|
|
600
|
+
});
|
|
601
|
+
}
|
|
452
602
|
if (spec.core && spec.core.retainReferenceDefinitions) {
|
|
453
603
|
instance.core.ruler.disable('strip_references');
|
|
454
604
|
}
|