securemark 0.222.0 → 0.225.0
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/CHANGELOG.md +17 -1
- package/dist/securemark.js +219 -249
- package/package-lock.json +63 -71
- package/package.json +7 -7
- package/src/parser/api/parse.test.ts +0 -11
- package/src/parser/inline/annotation.test.ts +2 -2
- package/src/parser/inline/annotation.ts +4 -4
- package/src/parser/inline/deletion.test.ts +0 -2
- package/src/parser/inline/deletion.ts +2 -2
- package/src/parser/inline/emphasis.test.ts +4 -4
- package/src/parser/inline/emphasis.ts +3 -3
- package/src/parser/inline/emstrong.ts +11 -11
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/html.test.ts +2 -2
- package/src/parser/inline/html.ts +8 -8
- package/src/parser/inline/insertion.test.ts +0 -2
- package/src/parser/inline/insertion.ts +2 -2
- package/src/parser/inline/link.test.ts +45 -24
- package/src/parser/inline/link.ts +23 -25
- package/src/parser/inline/mark.test.ts +4 -5
- package/src/parser/inline/mark.ts +3 -3
- package/src/parser/inline/math.test.ts +7 -2
- package/src/parser/inline/math.ts +2 -2
- package/src/parser/inline/media.test.ts +27 -16
- package/src/parser/inline/media.ts +33 -22
- package/src/parser/inline/reference.test.ts +2 -2
- package/src/parser/inline/reference.ts +6 -6
- package/src/parser/inline/ruby.ts +2 -2
- package/src/parser/inline/strong.test.ts +5 -5
- package/src/parser/inline/strong.ts +3 -3
- package/src/parser/inline.test.ts +4 -6
- package/src/parser/util.ts +51 -16
- package/src/renderer/render.ts +1 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { link } from './link';
|
|
2
2
|
import { some } from '../../combinator';
|
|
3
3
|
import { inspect } from '../../debug.test';
|
|
4
|
+
import { MarkdownParser } from '../../../markdown';
|
|
4
5
|
|
|
5
6
|
describe('Unit: parser/inline/link', () => {
|
|
6
7
|
describe('link', () => {
|
|
7
|
-
const parser = (source: string) => some(link)(source,
|
|
8
|
+
const parser = (source: string, context: MarkdownParser.Context = {}) => some(link)(source, context);
|
|
8
9
|
|
|
9
10
|
it('xss', () => {
|
|
10
11
|
assert.deepStrictEqual(inspect(parser('[]{javascript:alert}')), [['<a class="invalid">javascript:alert</a>'], '']);
|
|
@@ -50,33 +51,40 @@ describe('Unit: parser/inline/link', () => {
|
|
|
50
51
|
assert.deepStrictEqual(inspect(parser('[]{ }')), undefined);
|
|
51
52
|
assert.deepStrictEqual(inspect(parser('[]{ }')), undefined);
|
|
52
53
|
assert.deepStrictEqual(inspect(parser('[]{{}')), undefined);
|
|
53
|
-
assert.deepStrictEqual(inspect(parser('[]{{
|
|
54
|
-
assert.deepStrictEqual(inspect(parser('[]{
|
|
55
|
-
assert.deepStrictEqual(inspect(parser('[]{
|
|
56
|
-
assert.deepStrictEqual(inspect(parser('[]{
|
|
57
|
-
assert.deepStrictEqual(inspect(parser('[]{
|
|
54
|
+
assert.deepStrictEqual(inspect(parser('[]{{b}}')), undefined);
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('[]{b\nb}')), undefined);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('[]{b\\\nb}')), undefined);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser('[]{ b}')), undefined);
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('[]{ b\n}')), undefined);
|
|
58
59
|
assert.deepStrictEqual(inspect(parser('[ ]{}')), undefined);
|
|
59
60
|
assert.deepStrictEqual(inspect(parser('[ ]{ }')), undefined);
|
|
60
|
-
assert.deepStrictEqual(inspect(parser('[ ]{
|
|
61
|
-
assert.deepStrictEqual(inspect(parser('[ ]{
|
|
62
|
-
assert.deepStrictEqual(inspect(parser('[\n]{}')), undefined);
|
|
63
|
-
assert.deepStrictEqual(inspect(parser('[\\ ]{}')), undefined);
|
|
64
|
-
assert.deepStrictEqual(inspect(parser('[\\\n]{}')), undefined);
|
|
65
|
-
assert.deepStrictEqual(inspect(parser('[
|
|
66
|
-
assert.deepStrictEqual(inspect(parser('[]
|
|
61
|
+
assert.deepStrictEqual(inspect(parser('[ ]{b}')), undefined);
|
|
62
|
+
assert.deepStrictEqual(inspect(parser('[ ]{b}')), undefined);
|
|
63
|
+
assert.deepStrictEqual(inspect(parser('[\n]{b}')), undefined);
|
|
64
|
+
assert.deepStrictEqual(inspect(parser('[\\ ]{b}')), undefined);
|
|
65
|
+
assert.deepStrictEqual(inspect(parser('[\\\n]{b}')), undefined);
|
|
66
|
+
assert.deepStrictEqual(inspect(parser('[	]{b}')), undefined);
|
|
67
|
+
assert.deepStrictEqual(inspect(parser('[[]{b}')), undefined);
|
|
68
|
+
assert.deepStrictEqual(inspect(parser('[]]{b}')), undefined);
|
|
67
69
|
assert.deepStrictEqual(inspect(parser('[a]{}')), undefined);
|
|
68
|
-
assert.deepStrictEqual(inspect(parser('[ a]{b}')), undefined);
|
|
69
|
-
assert.deepStrictEqual(inspect(parser('[ a
|
|
70
|
-
assert.deepStrictEqual(inspect(parser('[a\nb]{
|
|
71
|
-
assert.deepStrictEqual(inspect(parser('[a\\\nb]{
|
|
72
|
-
assert.deepStrictEqual(inspect(parser('[<wbr>]{
|
|
73
|
-
assert.deepStrictEqual(inspect(parser('[[# a #]]{
|
|
70
|
+
assert.deepStrictEqual(inspect(parser('[\\ a]{b}')), undefined);
|
|
71
|
+
assert.deepStrictEqual(inspect(parser('[ \\ a]{b}')), undefined);
|
|
72
|
+
assert.deepStrictEqual(inspect(parser('[a\nb]{b}')), undefined);
|
|
73
|
+
assert.deepStrictEqual(inspect(parser('[a\\\nb]{b}')), undefined);
|
|
74
|
+
assert.deepStrictEqual(inspect(parser('[<wbr>]{b}')), undefined);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('[[# a #]]{b}')), undefined);
|
|
74
76
|
assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), undefined);
|
|
75
77
|
assert.deepStrictEqual(inspect(parser('[http://host]{http://host}')), undefined);
|
|
76
78
|
assert.deepStrictEqual(inspect(parser('[]{ttp://host}')), [['<a class="invalid">ttp://host</a>'], '']);
|
|
77
79
|
//assert.deepStrictEqual(inspect(parser('[]{http://[::ffff:0:0%1]}')), [['<a class="invalid">http://[::ffff:0:0%1]</a>'], '']);
|
|
78
80
|
//assert.deepStrictEqual(inspect(parser('[]{http://[::ffff:0:0/96]}')), [['<a class="invalid">http://[::ffff:0:0/96]</a>'], '']);
|
|
79
|
-
assert.deepStrictEqual(inspect(parser('
|
|
81
|
+
assert.deepStrictEqual(inspect(parser('[]{^/.}')), [[`<a class="invalid">^/.</a>`], '']);
|
|
82
|
+
assert.deepStrictEqual(inspect(parser('[]{^/..}')), [[`<a class="invalid">^/..</a>`], '']);
|
|
83
|
+
assert.deepStrictEqual(inspect(parser('[]{^/../}')), [[`<a class="invalid">^/../</a>`], '']);
|
|
84
|
+
assert.deepStrictEqual(inspect(parser('[]{^/../..}')), [[`<a class="invalid">^/../..</a>`], '']);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('[]{^/../b}')), [[`<a class="invalid">^/../b</a>`], '']);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser('[]{^/../b/..}')), [[`<a class="invalid">^/../b/..</a>`], '']);
|
|
87
|
+
assert.deepStrictEqual(inspect(parser(' []{b}')), undefined);
|
|
80
88
|
assert.deepStrictEqual(inspect(parser('![]{/}')), undefined);
|
|
81
89
|
});
|
|
82
90
|
|
|
@@ -91,15 +99,28 @@ describe('Unit: parser/inline/link', () => {
|
|
|
91
99
|
assert.deepStrictEqual(inspect(parser('[]{\\b}')), [[`<a href="\\b">\\b</a>`], '']);
|
|
92
100
|
assert.deepStrictEqual(inspect(parser('[]{?b=c+d&\\#}')), [['<a href="?b=c+d&\\#">?b=c+d&\\#</a>'], '']);
|
|
93
101
|
assert.deepStrictEqual(inspect(parser('[]{?&}')), [['<a href="?&amp;">?&amp;</a>'], '']);
|
|
94
|
-
assert.deepStrictEqual(inspect(parser('[]{./b}')), [['<a href="./b">./b</a>'], '']);
|
|
95
|
-
assert.deepStrictEqual(inspect(parser('[]{^/b}')), [[`<a href="/b">^/b</a>`], '']);
|
|
96
102
|
assert.deepStrictEqual(inspect(parser('[]{#}')), [['<a href="#">#</a>'], '']);
|
|
97
103
|
assert.deepStrictEqual(inspect(parser('[]{#b}')), [['<a href="#b">#b</a>'], '']);
|
|
104
|
+
assert.deepStrictEqual(inspect(parser('[]{./b}')), [['<a href="./b">./b</a>'], '']);
|
|
105
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}')), [[`<a href="/b">^/b</a>`], '']);
|
|
106
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b?/../}')), [[`<a href="/b?/../">^/b?/../</a>`], '']);
|
|
107
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b#/../}')), [[`<a href="/b#/../">^/b#/../</a>`], '']);
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/dir', location.origin) })), [[`<a href="/dir/b">^/b</a>`], '']);
|
|
109
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/dir/', location.origin) })), [[`<a href="/dir/b">^/b</a>`], '']);
|
|
110
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/folder/doc.md', location.origin) })), [[`<a href="/folder/b">^/b</a>`], '']);
|
|
111
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/folder/doc.md/', location.origin) })), [[`<a href="/folder/doc.md/b">^/b</a>`], '']);
|
|
112
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/.file', location.origin) })), [[`<a href="/b">^/b</a>`], '']);
|
|
113
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/0.0a', location.origin) })), [[`<a href="/b">^/b</a>`], '']);
|
|
114
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/0.a0', location.origin) })), [[`<a href="/b">^/b</a>`], '']);
|
|
115
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/0.0', location.origin) })), [[`<a href="/0.0/b">^/b</a>`], '']);
|
|
116
|
+
assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/0.0,0.0,0z', location.origin) })), [[`<a href="/0.0,0.0,0z/b">^/b</a>`], '']);
|
|
117
|
+
assert.deepStrictEqual(inspect(parser('[ a]{b}')), [['<a href="b">a</a>'], '']);
|
|
118
|
+
assert.deepStrictEqual(inspect(parser('[ a ]{b}')), [['<a href="b">a</a>'], '']);
|
|
119
|
+
assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
|
|
120
|
+
assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
|
|
98
121
|
assert.deepStrictEqual(inspect(parser('[a]{b}')), [['<a href="b">a</a>'], '']);
|
|
99
122
|
assert.deepStrictEqual(inspect(parser('[a]{#}')), [['<a href="#">a</a>'], '']);
|
|
100
123
|
assert.deepStrictEqual(inspect(parser('[a]{#b}')), [['<a href="#b">a</a>'], '']);
|
|
101
|
-
assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
|
|
102
|
-
assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
|
|
103
124
|
assert.deepStrictEqual(inspect(parser('[a b]{c}')), [['<a href="c">a b</a>'], '']);
|
|
104
125
|
assert.deepStrictEqual(inspect(parser(`[]{?#${encodeURIComponent(':/[]{}<>?#=& ')}}`)), [['<a href="?#%3A%2F%5B%5D%7B%7D%3C%3E%3F%23%3D%26%20">?#%3A%2F[]{}<>%3F%23%3D%26%20</a>'], '']);
|
|
105
126
|
assert.deepStrictEqual(inspect(parser('{b}')), [['<a href="b">b</a>'], '']);
|
|
@@ -7,7 +7,7 @@ import { inline, media, shortmedia } from '../inline';
|
|
|
7
7
|
import { attributes } from './html';
|
|
8
8
|
import { autolink } from '../autolink';
|
|
9
9
|
import { str } from '../source';
|
|
10
|
-
import {
|
|
10
|
+
import { startLoose, trimNode, stringify } from '../util';
|
|
11
11
|
import { html, define, defrag } from 'typed-dom';
|
|
12
12
|
import { ReadonlyURL } from 'spica/url';
|
|
13
13
|
|
|
@@ -28,7 +28,7 @@ export const link: LinkParser = lazy(() => creator(10, bind(reverse(
|
|
|
28
28
|
surround('[', shortmedia, ']'),
|
|
29
29
|
surround(
|
|
30
30
|
'[',
|
|
31
|
-
|
|
31
|
+
startLoose(
|
|
32
32
|
context({ syntax: { inline: {
|
|
33
33
|
annotation: false,
|
|
34
34
|
reference: false,
|
|
@@ -39,7 +39,7 @@ export const link: LinkParser = lazy(() => creator(10, bind(reverse(
|
|
|
39
39
|
media: false,
|
|
40
40
|
autolink: false,
|
|
41
41
|
}}},
|
|
42
|
-
some(inline, ']', /^\\?\n/))),
|
|
42
|
+
some(inline, ']', /^\\?\n/)), ']'),
|
|
43
43
|
']',
|
|
44
44
|
true),
|
|
45
45
|
]))),
|
|
@@ -54,9 +54,9 @@ export const link: LinkParser = lazy(() => creator(10, bind(reverse(
|
|
|
54
54
|
assert(!INSECURE_URI.match(/\s/));
|
|
55
55
|
const el = create(
|
|
56
56
|
INSECURE_URI,
|
|
57
|
-
|
|
57
|
+
trimNode(defrag(content)),
|
|
58
58
|
new ReadonlyURL(
|
|
59
|
-
resolve(INSECURE_URI, context.host
|
|
59
|
+
resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
|
|
60
60
|
context.host?.href || location.href),
|
|
61
61
|
context.host?.origin || location.origin);
|
|
62
62
|
if (el.classList.contains('invalid')) return [[el], rest];
|
|
@@ -81,33 +81,25 @@ export function resolve(uri: string, host: URL | Location, source: URL | Locatio
|
|
|
81
81
|
assert(uri === uri.trim());
|
|
82
82
|
switch (true) {
|
|
83
83
|
case uri.slice(0, 2) === '^/':
|
|
84
|
-
const
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
const last = host.pathname.slice(host.pathname.lastIndexOf('/') + 1);
|
|
85
|
+
return last.includes('.') // isFile
|
|
86
|
+
&& /^[0-9]*[a-z][0-9a-z]*$/i.test(last.slice(last.lastIndexOf('.') + 1))
|
|
87
|
+
? `${host.pathname.slice(0, -last.length)}${uri.slice(2)}`
|
|
88
|
+
: `${host.pathname.replace(/\/?$/, '/')}${uri.slice(2)}`;
|
|
88
89
|
case host.origin === source.origin
|
|
89
90
|
&& host.pathname === source.pathname:
|
|
90
91
|
case uri.slice(0, 2) === '//':
|
|
91
92
|
return uri;
|
|
92
93
|
default:
|
|
93
94
|
const target = new ReadonlyURL(uri, source.href);
|
|
94
|
-
return target.origin ===
|
|
95
|
-
? uri
|
|
96
|
-
: target.origin === host.origin
|
|
95
|
+
return target.origin === host.origin
|
|
97
96
|
? target.href.slice(target.origin.length)
|
|
98
97
|
: target.href;
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
function fillTrailingSlash(pathname: string): string {
|
|
103
|
-
assert(pathname);
|
|
104
|
-
return pathname[pathname.length - 1] === '/'
|
|
105
|
-
? pathname
|
|
106
|
-
: pathname + '/';
|
|
107
|
-
}
|
|
108
|
-
|
|
109
101
|
function create(
|
|
110
|
-
|
|
102
|
+
INSECURE_URI: string,
|
|
111
103
|
content: readonly (string | HTMLElement)[],
|
|
112
104
|
uri: ReadonlyURL,
|
|
113
105
|
origin: string,
|
|
@@ -118,6 +110,12 @@ function create(
|
|
|
118
110
|
case 'http:':
|
|
119
111
|
case 'https:':
|
|
120
112
|
assert(uri.host);
|
|
113
|
+
if (INSECURE_URI.slice(0, 2) === '^/' &&
|
|
114
|
+
/\/\.\.?(?:\/|$)/.test(INSECURE_URI.slice(0, INSECURE_URI.search(/[?#]|$/)))) {
|
|
115
|
+
type = 'argument';
|
|
116
|
+
description = 'Dot-segments cannot be used in subresource paths.';
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
121
119
|
return html('a',
|
|
122
120
|
{
|
|
123
121
|
href: uri.source,
|
|
@@ -128,19 +126,19 @@ function create(
|
|
|
128
126
|
: undefined,
|
|
129
127
|
},
|
|
130
128
|
content.length === 0
|
|
131
|
-
? decode(
|
|
129
|
+
? decode(INSECURE_URI)
|
|
132
130
|
: content);
|
|
133
131
|
case 'tel:':
|
|
134
132
|
if (content.length === 0) {
|
|
135
|
-
content = [
|
|
133
|
+
content = [INSECURE_URI];
|
|
136
134
|
}
|
|
137
135
|
const pattern = /^(?:tel:)?(?:\+(?!0))?\d+(?:-\d+)*$/i;
|
|
138
136
|
switch (true) {
|
|
139
137
|
case content.length === 1
|
|
140
138
|
&& typeof content[0] === 'string'
|
|
141
|
-
&& pattern.test(
|
|
139
|
+
&& pattern.test(INSECURE_URI)
|
|
142
140
|
&& pattern.test(content[0])
|
|
143
|
-
&&
|
|
141
|
+
&& INSECURE_URI.replace(/[^+\d]/g, '') === content[0].replace(/[^+\d]/g, ''):
|
|
144
142
|
return html('a', { href: uri.source }, content);
|
|
145
143
|
}
|
|
146
144
|
type = 'content';
|
|
@@ -155,7 +153,7 @@ function create(
|
|
|
155
153
|
'data-invalid-description': description ??= 'Invalid protocol.',
|
|
156
154
|
},
|
|
157
155
|
content.length === 0
|
|
158
|
-
?
|
|
156
|
+
? INSECURE_URI
|
|
159
157
|
: content);
|
|
160
158
|
}
|
|
161
159
|
|
|
@@ -12,7 +12,10 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('==')), undefined);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('==a')), [['==', 'a'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('==a=')), [['==', 'a', '='], '']);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser('==a
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' '], '==']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a', '<br>'], '==']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a', ' '], '==']);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a', '<span class="linebreak"> </span>'], '==']);
|
|
16
19
|
assert.deepStrictEqual(inspect(parser('== ==')), undefined);
|
|
17
20
|
assert.deepStrictEqual(inspect(parser('== a==')), undefined);
|
|
18
21
|
assert.deepStrictEqual(inspect(parser('== a ==')), undefined);
|
|
@@ -26,14 +29,10 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
26
29
|
it('basic', () => {
|
|
27
30
|
assert.deepStrictEqual(inspect(parser('==a==')), [['<mark>a</mark>'], '']);
|
|
28
31
|
assert.deepStrictEqual(inspect(parser('==ab==')), [['<mark>ab</mark>'], '']);
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('==a ==')), [['<mark>a </mark>'], '']);
|
|
30
|
-
assert.deepStrictEqual(inspect(parser('==a\n==')), [['<mark>a</mark>'], '']);
|
|
31
32
|
assert.deepStrictEqual(inspect(parser('==a\nb==')), [['<mark>a<br>b</mark>'], '']);
|
|
32
33
|
assert.deepStrictEqual(inspect(parser('==a\\\nb==')), [['<mark>a<span class="linebreak"> </span>b</mark>'], '']);
|
|
33
34
|
assert.deepStrictEqual(inspect(parser('==\\===')), [['<mark>=</mark>'], '']);
|
|
34
35
|
assert.deepStrictEqual(inspect(parser('==a===')), [['<mark>a</mark>'], '=']);
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('===a==')), [['<mark>=a</mark>'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser('===a===')), [['<mark>=a</mark>'], '=']);
|
|
37
36
|
});
|
|
38
37
|
|
|
39
38
|
it('nest', () => {
|
|
@@ -2,7 +2,7 @@ import { MarkParser } from '../inline';
|
|
|
2
2
|
import { union, some, creator, surround, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
|
-
import { startTight,
|
|
5
|
+
import { startTight, isEndTightNodes } from '../util';
|
|
6
6
|
import { html, defrag } from 'typed-dom';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ export const mark: MarkParser = lazy(() => creator(surround(
|
|
|
11
11
|
startTight(union([some(inline, '==')])),
|
|
12
12
|
str('=='), false,
|
|
13
13
|
([as, bs, cs], rest) =>
|
|
14
|
-
|
|
15
|
-
? [[html('mark', defrag(
|
|
14
|
+
isEndTightNodes(bs)
|
|
15
|
+
? [[html('mark', defrag(bs))], rest]
|
|
16
16
|
: [unshift(as, bs), cs[0] + rest],
|
|
17
17
|
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
@@ -23,6 +23,7 @@ describe('Unit: parser/inline/math', () => {
|
|
|
23
23
|
assert.deepStrictEqual(inspect(parser('$-0$-1')), undefined);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser('$-a$')), undefined);
|
|
25
25
|
assert.deepStrictEqual(inspect(parser('$-a$-b')), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('$a $')), undefined);
|
|
26
27
|
assert.deepStrictEqual(inspect(parser('$a-b$')), undefined);
|
|
27
28
|
assert.deepStrictEqual(inspect(parser('$a-b$c-d')), undefined);
|
|
28
29
|
assert.deepStrictEqual(inspect(parser('$a+b$')), undefined);
|
|
@@ -33,6 +34,8 @@ describe('Unit: parser/inline/math', () => {
|
|
|
33
34
|
assert.deepStrictEqual(inspect(parser('$a$b')), undefined);
|
|
34
35
|
assert.deepStrictEqual(inspect(parser('$a$b$')), undefined);
|
|
35
36
|
assert.deepStrictEqual(inspect(parser('$ $')), undefined);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser('$ a$')), undefined);
|
|
38
|
+
assert.deepStrictEqual(inspect(parser('$ a $')), undefined);
|
|
36
39
|
assert.deepStrictEqual(inspect(parser('$\n$')), undefined);
|
|
37
40
|
assert.deepStrictEqual(inspect(parser('$a\nb$')), undefined);
|
|
38
41
|
assert.deepStrictEqual(inspect(parser('$a\\\nb$')), undefined);
|
|
@@ -59,6 +62,7 @@ describe('Unit: parser/inline/math', () => {
|
|
|
59
62
|
assert.deepStrictEqual(inspect(parser('${}$')), [['<span class="math" translate="no" data-src="${}$">${}$</span>'], '']);
|
|
60
63
|
assert.deepStrictEqual(inspect(parser('${ }$')), [['<span class="math" translate="no" data-src="${ }$">${ }$</span>'], '']);
|
|
61
64
|
assert.deepStrictEqual(inspect(parser('${a}$')), [['<span class="math" translate="no" data-src="${a}$">${a}$</span>'], '']);
|
|
65
|
+
assert.deepStrictEqual(inspect(parser('${a}$$')), [['<span class="math" translate="no" data-src="${a}$">${a}$</span>'], '$']);
|
|
62
66
|
assert.deepStrictEqual(inspect(parser('${a}$0')), [['<span class="math" translate="no" data-src="${a}$">${a}$</span>'], '0']);
|
|
63
67
|
assert.deepStrictEqual(inspect(parser('${a}$b')), [['<span class="math" translate="no" data-src="${a}$">${a}$</span>'], 'b']);
|
|
64
68
|
assert.deepStrictEqual(inspect(parser('${ab}$')), [['<span class="math" translate="no" data-src="${ab}$">${ab}$</span>'], '']);
|
|
@@ -71,14 +75,15 @@ describe('Unit: parser/inline/math', () => {
|
|
|
71
75
|
assert.deepStrictEqual(inspect(parser('${\\$}$')), [['<span class="math" translate="no" data-src="${\\$}$">${\\$}$</span>'], '']);
|
|
72
76
|
assert.deepStrictEqual(inspect(parser('${\\\\}$')), [['<span class="math" translate="no" data-src="${\\\\}$">${\\\\}$</span>'], '']);
|
|
73
77
|
assert.deepStrictEqual(inspect(parser('$a$')), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '']);
|
|
78
|
+
assert.deepStrictEqual(inspect(parser('$a$$')), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '$']);
|
|
74
79
|
assert.deepStrictEqual(inspect(parser(`$a'$`)), [[`<span class="math" translate="no" data-src="$a'$">$a'$</span>`], '']);
|
|
75
80
|
assert.deepStrictEqual(inspect(parser(`$a''$`)), [[`<span class="math" translate="no" data-src="$a''$">$a''$</span>`], '']);
|
|
76
81
|
assert.deepStrictEqual(inspect(parser('$a$[A](a)')), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '[A](a)']);
|
|
77
|
-
assert.deepStrictEqual(inspect(parser('$a$$')), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '$']);
|
|
78
82
|
assert.deepStrictEqual(inspect(parser('$A$')), [['<span class="math" translate="no" data-src="$A$">$A$</span>'], '']);
|
|
79
83
|
assert.deepStrictEqual(inspect(parser('$\\$$')), [['<span class="math" translate="no" data-src="$\\$$">$\\$$</span>'], '']);
|
|
80
84
|
assert.deepStrictEqual(inspect(parser('$\\Pi$')), [['<span class="math" translate="no" data-src="$\\Pi$">$\\Pi$</span>'], '']);
|
|
81
|
-
assert.deepStrictEqual(inspect(parser('$\\
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('$\\ 0$')), [['<span class="math" translate="no" data-src="$\\ 0$">$\\ 0$</span>'], '']);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser('$\\\\0$')), [['<span class="math" translate="no" data-src="$\\\\0$">$\\\\0$</span>'], '']);
|
|
82
87
|
assert.deepStrictEqual(inspect(parser('$|1|$')), [['<span class="math" translate="no" data-src="$|1|$">$|1|$</span>'], '']);
|
|
83
88
|
assert.deepStrictEqual(inspect(parser('$[0,1)$]')), [['<span class="math" translate="no" data-src="$[0,1)$">$[0,1)$</span>'], ']']);
|
|
84
89
|
assert.deepStrictEqual(inspect(parser('$(0, 1]$)')), [['<span class="math" translate="no" data-src="$(0, 1]$">$(0, 1]$</span>'], ')']);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MathParser } from '../inline';
|
|
2
2
|
import { union, some, validate, verify, rewrite, creator, surround, lazy } from '../../combinator';
|
|
3
3
|
import { escsource, str } from '../source';
|
|
4
|
-
import {
|
|
4
|
+
import { isEndTightNodes } from '../util';
|
|
5
5
|
import { html } from 'typed-dom';
|
|
6
6
|
|
|
7
7
|
const disallowedCommand = /\\(?:begin|tiny|huge|large)(?![0-9a-z])/i;
|
|
@@ -21,7 +21,7 @@ export const math: MathParser = lazy(() => creator(validate('$', '$', '\n', rewr
|
|
|
21
21
|
// $[A-z]*[,.!?()] : Incomplete syntax before texts
|
|
22
22
|
// $[A-z]*\s?[!@#&*+~=`$[]{<] : Incomplete syntax in or around another syntax
|
|
23
23
|
str(/^(?=[\\^_[(|]|[A-Za-z][0-9A-Za-z]*'*[ ~]?(?:\$|([\\^_(|:=<>])(?!\1)))(?:\\\$|[\x20-\x23\x25-\x7E])*/),
|
|
24
|
-
|
|
24
|
+
isEndTightNodes),
|
|
25
25
|
/^\$(?![0-9A-Za-z])/),
|
|
26
26
|
]),
|
|
27
27
|
(source, { caches: { math: cache } = {} }) => [[
|
|
@@ -29,26 +29,34 @@ describe('Unit: parser/inline/media', () => {
|
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('![]{ }')), undefined);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('![]]{/}')), undefined);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('![]{{}')), undefined);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('![]{{
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
34
|
-
assert.deepStrictEqual(inspect(parser('![]{a\\\
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
36
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
37
|
-
assert.deepStrictEqual(inspect(parser('![ ]{
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
39
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
40
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('![]{{b}}')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('![]{b\nc}')), undefined);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('![]{a\\\nc}')), undefined);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('![]{ b}')), undefined);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('![]{ b\n}')), undefined);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser('![ ]{}')), undefined);
|
|
38
|
+
assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('![\n]{b}')), undefined);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser('![\\ ]{b}')), undefined);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('![\\\n]{b}')), undefined);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('![	]{b}')), undefined);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('![[]{b}')), undefined);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser('![]]{b}')), undefined);
|
|
41
46
|
assert.deepStrictEqual(inspect(parser('![a]{}')), undefined);
|
|
42
|
-
assert.deepStrictEqual(inspect(parser('![ a]{
|
|
43
|
-
assert.deepStrictEqual(inspect(parser('![ a ]{
|
|
44
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
45
|
-
assert.deepStrictEqual(inspect(parser('![a
|
|
46
|
-
assert.deepStrictEqual(inspect(parser('![a\\\nb]{#}')), undefined);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser('![\\ a ]{b}')), undefined);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('![ \\ a ]{b}')), undefined);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser('![a\nb]{b}')), undefined);
|
|
50
|
+
assert.deepStrictEqual(inspect(parser('![a\\\nb]{b}')), undefined);
|
|
47
51
|
assert.deepStrictEqual(inspect(parser('![]{ttp://host}')), [['<img class="media invalid" data-src="ttp://host" alt="">'], '']);
|
|
48
52
|
assert.deepStrictEqual(inspect(parser('![]{tel:1234567890}')), [['<img class="media invalid" data-src="tel:1234567890" alt="">'], '']);
|
|
49
53
|
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0%1]}')), [['<img class="media invalid" alt="">'], '']);
|
|
50
54
|
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0/96]}')), [['<img class="media invalid" alt="">'], '']);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('![]{.}')), [['<img class="media invalid" data-src="." alt="">'], '']);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('![]{..}')), [['<img class="media invalid" data-src=".." alt="">'], '']);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser('![]{../}')), [['<img class="media invalid" data-src="../" alt="">'], '']);
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('![]{/../b}')), [['<img class="media invalid" data-src="/../b" alt="">'], '']);
|
|
59
|
+
assert.deepStrictEqual(inspect(parser(' ![]{b}')), undefined);
|
|
52
60
|
assert.deepStrictEqual(inspect(parser('[]{/}')), undefined);
|
|
53
61
|
});
|
|
54
62
|
|
|
@@ -61,8 +69,11 @@ describe('Unit: parser/inline/media', () => {
|
|
|
61
69
|
assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
62
70
|
assert.deepStrictEqual(inspect(parser('![]{\\ }')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
63
71
|
assert.deepStrictEqual(inspect(parser('![]{\\b}')), [['<a href="\\b" target="_blank"><img class="media" data-src="\\b" alt=""></a>'], '']);
|
|
64
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
72
|
+
assert.deepStrictEqual(inspect(parser('![]{?/../}')), [[`<a href="?/../" target="_blank"><img class="media" data-src="?/../" alt=""></a>`], '']);
|
|
73
|
+
assert.deepStrictEqual(inspect(parser('![]{#/../}')), [[`<a href="#/../" target="_blank"><img class="media" data-src="#/../" alt=""></a>`], '']);
|
|
65
74
|
assert.deepStrictEqual(inspect(parser('![]{^/b}')), [[`<a href="/b" target="_blank"><img class="media" data-src="/b" alt=""></a>`], '']);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('![ a]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
76
|
+
assert.deepStrictEqual(inspect(parser('![ a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
66
77
|
assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
67
78
|
assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
68
79
|
assert.deepStrictEqual(inspect(parser('![a b]{c}')), [['<a href="c" target="_blank"><img class="media" data-src="c" alt="a b"></a>'], '']);
|
|
@@ -6,7 +6,6 @@ import { link, uri, option as linkoption, resolve } from './link';
|
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { htmlentity } from './htmlentity';
|
|
8
8
|
import { txt, str } from '../source';
|
|
9
|
-
import { verifyStartTight } from '../util';
|
|
10
9
|
import { html, define } from 'typed-dom';
|
|
11
10
|
import { ReadonlyURL } from 'spica/url';
|
|
12
11
|
import { unshift, push, join } from 'spica/array';
|
|
@@ -24,28 +23,29 @@ export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
|
|
|
24
23
|
validate(['[', '{'], '}', '\n',
|
|
25
24
|
guard(context => context.syntax?.inline?.media ?? true,
|
|
26
25
|
tails([
|
|
27
|
-
dup(surround(/^\[(
|
|
26
|
+
dup(surround(/^\[(?!\s*\\\s)/, some(union([htmlentity, bracket, txt]), ']', /^\\?\n/), ']', true)),
|
|
28
27
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
|
|
29
28
|
])))),
|
|
30
|
-
([as, bs]) => bs ? [[join(as)], bs] : [[''], as]),
|
|
31
|
-
([[text]]) =>
|
|
29
|
+
([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
|
|
30
|
+
([[text]]) => text === '' || text.trim() !== ''),
|
|
32
31
|
([[text], params], rest, context) => {
|
|
33
32
|
const INSECURE_URI = params.shift()!;
|
|
34
33
|
assert(INSECURE_URI === INSECURE_URI.trim());
|
|
35
34
|
assert(!INSECURE_URI.match(/\s/));
|
|
36
35
|
const url = new ReadonlyURL(
|
|
37
|
-
resolve(INSECURE_URI, context.host
|
|
36
|
+
resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
|
|
38
37
|
context.host?.href || location.href);
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!
|
|
45
|
-
|
|
38
|
+
let cache: HTMLElement | undefined;
|
|
39
|
+
const el = undefined
|
|
40
|
+
|| (cache = context.caches?.media?.get(url.href)?.cloneNode(true))
|
|
41
|
+
|| html('img', { class: 'media', 'data-src': url.source, alt: text });
|
|
42
|
+
assert(!el.matches('.invalid'));
|
|
43
|
+
if (!cache && !sanitize(url, el)) return [[el], rest];
|
|
44
|
+
assert(!el.matches('.invalid'));
|
|
45
|
+
cache?.hasAttribute('alt') && cache?.setAttribute('alt', text);
|
|
46
46
|
define(el, attributes('media', push([], el.classList), optspec, params));
|
|
47
47
|
assert(el.matches('img') || !el.matches('.invalid'));
|
|
48
|
-
if (context.syntax?.inline?.link === false ||
|
|
48
|
+
if (context.syntax?.inline?.link === false || cache && cache.tagName !== 'IMG') return [[el], rest];
|
|
49
49
|
return fmap(
|
|
50
50
|
link as MediaParser,
|
|
51
51
|
([link]) => [define(link, { target: '_blank' }, [el])])
|
|
@@ -67,18 +67,29 @@ const option: MediaParser.ParameterParser.OptionParser = union([
|
|
|
67
67
|
|
|
68
68
|
function sanitize(uri: ReadonlyURL, target: HTMLElement): boolean {
|
|
69
69
|
assert(target.tagName === 'IMG');
|
|
70
|
+
assert(!target.matches('.invalid'));
|
|
71
|
+
if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
|
|
72
|
+
define(target, {
|
|
73
|
+
class: void target.classList.add('invalid'),
|
|
74
|
+
'data-invalid-syntax': 'media',
|
|
75
|
+
'data-invalid-type': 'argument',
|
|
76
|
+
'data-invalid-description': 'Dot-segments cannot be used in media paths; use subresource paths instead.',
|
|
77
|
+
});
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
70
80
|
switch (uri.protocol) {
|
|
71
81
|
case 'http:':
|
|
72
82
|
case 'https:':
|
|
73
83
|
assert(uri.host);
|
|
74
|
-
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
define(target, {
|
|
87
|
+
class: void target.classList.add('invalid'),
|
|
88
|
+
'data-invalid-syntax': 'media',
|
|
89
|
+
'data-invalid-type': 'argument',
|
|
90
|
+
'data-invalid-description': 'Invalid protocol.',
|
|
91
|
+
});
|
|
92
|
+
return false;
|
|
75
93
|
}
|
|
76
|
-
|
|
77
|
-
define(target, {
|
|
78
|
-
class: void target.classList.add('invalid'),
|
|
79
|
-
'data-invalid-syntax': 'media',
|
|
80
|
-
'data-invalid-type': 'argument',
|
|
81
|
-
'data-invalid-description': 'Invalid protocol.',
|
|
82
|
-
});
|
|
83
|
-
return false;
|
|
94
|
+
return true;
|
|
84
95
|
}
|
|
@@ -14,8 +14,6 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('[[]]')), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('[[]]]')), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('[[ ]]')), undefined);
|
|
17
|
-
assert.deepStrictEqual(inspect(parser('[[ a]]')), undefined);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser('[[ a ]]')), undefined);
|
|
19
17
|
assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
|
|
20
18
|
assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
|
|
21
19
|
assert.deepStrictEqual(inspect(parser('[[\\ a]]')), undefined);
|
|
@@ -34,6 +32,8 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
34
32
|
});
|
|
35
33
|
|
|
36
34
|
it('basic', () => {
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('[[ a]]')), [['<sup class="reference">a</sup>'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('[[ a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
37
37
|
assert.deepStrictEqual(inspect(parser('[[a]]')), [['<sup class="reference">a</sup>'], '']);
|
|
38
38
|
assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
39
39
|
assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
@@ -3,13 +3,13 @@ import { ReferenceParser } from '../inline';
|
|
|
3
3
|
import { union, subsequence, some, validate, verify, focus, guard, context, creator, surround, lazy, fmap } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { str } from '../source';
|
|
6
|
-
import {
|
|
6
|
+
import { startLoose, isStartLoose, trimNode, stringify } from '../util';
|
|
7
7
|
import { html, defrag } from 'typed-dom';
|
|
8
8
|
|
|
9
9
|
export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
|
|
10
10
|
'[[',
|
|
11
11
|
guard(context => context.syntax?.inline?.reference ?? true,
|
|
12
|
-
|
|
12
|
+
startLoose(
|
|
13
13
|
context({ syntax: { inline: {
|
|
14
14
|
annotation: false,
|
|
15
15
|
reference: false,
|
|
@@ -24,15 +24,15 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
|
|
|
24
24
|
abbr,
|
|
25
25
|
focus('^', c => [['', c], '']),
|
|
26
26
|
some(inline, ']', /^\\?\n/),
|
|
27
|
-
])))),
|
|
27
|
+
])), ']]')),
|
|
28
28
|
']]'),
|
|
29
|
-
ns => [html('sup', attributes(ns),
|
|
29
|
+
ns => [html('sup', attributes(ns), trimNode(defrag(ns)))]))));
|
|
30
30
|
|
|
31
31
|
const abbr: ReferenceParser.AbbrParser = creator(fmap(verify(surround(
|
|
32
32
|
'^',
|
|
33
33
|
union([str(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]),
|
|
34
|
-
/^\|?(?=]])|^\|[^\S\n]
|
|
35
|
-
(_, rest, context) =>
|
|
34
|
+
/^\|?(?=]])|^\|[^\S\n]/),
|
|
35
|
+
(_, rest, context) => isStartLoose(rest, context)),
|
|
36
36
|
([source]) => [html('abbr', source)]));
|
|
37
37
|
|
|
38
38
|
function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
|
|
@@ -4,7 +4,7 @@ import { eval, exec } from '../../combinator/data/parser';
|
|
|
4
4
|
import { sequence, validate, verify, focus, creator, surround, lazy, bind } from '../../combinator';
|
|
5
5
|
import { htmlentity } from './htmlentity';
|
|
6
6
|
import { text as txt } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { isStartTightNodes } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom';
|
|
9
9
|
import { unshift, push, join } from 'spica/array';
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ export const ruby: RubyParser = lazy(() => creator(bind(verify(
|
|
|
14
14
|
surround('[', focus(/^(?:\\[^\n]|[^\[\]\n])+(?=]\()/, text), ']'),
|
|
15
15
|
surround('(', focus(/^(?:\\[^\n]|[^\(\)\n])+(?=\))/, text), ')'),
|
|
16
16
|
])),
|
|
17
|
-
([texts]) =>
|
|
17
|
+
([texts]) => isStartTightNodes(texts)),
|
|
18
18
|
([texts, rubies], rest) => {
|
|
19
19
|
const tail = typeof texts[texts.length - 1] === 'object'
|
|
20
20
|
? [texts.pop()!]
|
|
@@ -10,7 +10,10 @@ describe('Unit: parser/inline/strong', () => {
|
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('**')), undefined);
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('**a')), [['**', 'a'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
|
|
13
|
-
assert.deepStrictEqual(inspect(parser('**a
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' '], '**']);
|
|
14
|
+
assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a', '<br>'], '**']);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' '], '**']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>'], '**']);
|
|
14
17
|
assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
|
|
15
18
|
assert.deepStrictEqual(inspect(parser('** **')), undefined);
|
|
16
19
|
assert.deepStrictEqual(inspect(parser('** a**')), undefined);
|
|
@@ -27,15 +30,12 @@ describe('Unit: parser/inline/strong', () => {
|
|
|
27
30
|
|
|
28
31
|
it('basic', () => {
|
|
29
32
|
assert.deepStrictEqual(inspect(parser('**a**')), [['<strong>a</strong>'], '']);
|
|
30
|
-
assert.deepStrictEqual(inspect(parser('**a **')), [['<strong>a </strong>'], '']);
|
|
31
|
-
assert.deepStrictEqual(inspect(parser('**a\n**')), [['<strong>a</strong>'], '']);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['<strong>a<span class="linebreak"> </span></strong>'], '']);
|
|
33
33
|
assert.deepStrictEqual(inspect(parser('**ab**')), [['<strong>ab</strong>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser('**a\nb**')), [['<strong>a<br>b</strong>'], '']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser('**a\\\nb**')), [['<strong>a<span class="linebreak"> </span>b</strong>'], '']);
|
|
36
36
|
assert.deepStrictEqual(inspect(parser('**a*b*c**')), [['<strong>a<em>b</em>c</strong>'], '']);
|
|
37
37
|
assert.deepStrictEqual(inspect(parser('**a*b*c**d')), [['<strong>a<em>b</em>c</strong>'], 'd']);
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('**a
|
|
38
|
+
assert.deepStrictEqual(inspect(parser('**a *b***')), [['<strong>a <em>b</em></strong>'], '']);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('nest', () => {
|