securemark 0.279.1 → 0.280.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 +6 -0
- package/README.md +10 -10
- package/dist/index.js +116 -98
- package/markdown.d.ts +1 -1
- package/package.json +1 -1
- package/src/combinator/data/parser/context/delimiter.ts +49 -21
- package/src/combinator/data/parser/context/memo.ts +6 -6
- package/src/combinator/data/parser/context.ts +23 -7
- package/src/parser/api/parse.test.ts +13 -13
- package/src/parser/block/extension/table.ts +1 -1
- package/src/parser/block.ts +2 -2
- package/src/parser/inline/annotation.ts +4 -4
- package/src/parser/inline/autolink/account.ts +1 -1
- package/src/parser/inline/autolink/url.ts +1 -1
- package/src/parser/inline/autolink.ts +2 -2
- package/src/parser/inline/bracket.test.ts +3 -2
- package/src/parser/inline/bracket.ts +8 -9
- package/src/parser/inline/deletion.ts +4 -4
- package/src/parser/inline/emphasis.ts +4 -4
- package/src/parser/inline/emstrong.ts +4 -4
- package/src/parser/inline/extension/index.test.ts +6 -0
- package/src/parser/inline/extension/index.ts +11 -11
- package/src/parser/inline/extension/placeholder.ts +4 -4
- package/src/parser/inline/html.test.ts +1 -1
- package/src/parser/inline/html.ts +5 -5
- package/src/parser/inline/insertion.ts +4 -4
- package/src/parser/inline/link.ts +6 -6
- package/src/parser/inline/mark.ts +4 -4
- package/src/parser/inline/media.ts +4 -4
- package/src/parser/inline/reference.ts +3 -3
- package/src/parser/inline/remark.test.ts +1 -0
- package/src/parser/inline/remark.ts +4 -4
- package/src/parser/inline/ruby.ts +2 -2
- package/src/parser/inline/strong.ts +4 -4
- package/src/parser/inline/template.ts +7 -4
- package/src/parser/inline.test.ts +2 -5
- package/src/parser/source/str.ts +0 -19
- package/src/parser/source/text.test.ts +1 -1
- package/src/parser/source/text.ts +3 -3
- package/src/parser/source.ts +1 -1
- package/src/parser/visibility.ts +3 -1
package/markdown.d.ts
CHANGED
|
@@ -784,8 +784,8 @@ export namespace MarkdownParser {
|
|
|
784
784
|
// [#index|signature]
|
|
785
785
|
Inline<'extension/index'>,
|
|
786
786
|
Parser<HTMLAnchorElement, Context, [
|
|
787
|
-
IndexParser.SignatureParser,
|
|
788
787
|
InlineParser,
|
|
788
|
+
IndexParser.SignatureParser,
|
|
789
789
|
]> {
|
|
790
790
|
}
|
|
791
791
|
export namespace IndexParser {
|
package/package.json
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { memoize, reduce } from 'spica/memoize';
|
|
2
2
|
|
|
3
|
+
interface Delimiter {
|
|
4
|
+
readonly index: number;
|
|
5
|
+
readonly signature: string;
|
|
6
|
+
readonly matcher: (source: string) => boolean | undefined;
|
|
7
|
+
readonly precedence: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
export class Delimiters {
|
|
4
11
|
public static signature(pattern: string | RegExp | undefined): string {
|
|
5
12
|
switch (typeof pattern) {
|
|
@@ -23,43 +30,64 @@ export class Delimiters {
|
|
|
23
30
|
}
|
|
24
31
|
},
|
|
25
32
|
this.signature);
|
|
26
|
-
private readonly
|
|
27
|
-
private readonly
|
|
28
|
-
private
|
|
33
|
+
private readonly registry = memoize<(signature: string) => Delimiter[]>(() => []);
|
|
34
|
+
private readonly delimiters: Delimiter[] = [];
|
|
35
|
+
private readonly order: number[] = [];
|
|
29
36
|
public push(
|
|
30
|
-
...
|
|
37
|
+
...delims: readonly {
|
|
31
38
|
readonly signature: string;
|
|
32
39
|
readonly matcher: (source: string) => boolean | undefined;
|
|
33
40
|
readonly precedence?: number;
|
|
34
41
|
}[]
|
|
35
42
|
): void {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
const { registry, delimiters, order } = this;
|
|
44
|
+
for (let i = 0; i < delims.length; ++i) {
|
|
45
|
+
const { signature, matcher, precedence = 1 } = delims[i];
|
|
46
|
+
const stack = registry(signature);
|
|
47
|
+
const index = stack[0]?.index ?? delimiters.length;
|
|
48
|
+
if (stack.length === 0 || precedence > delimiters[index].precedence) {
|
|
49
|
+
const delimiter: Delimiter = {
|
|
50
|
+
index,
|
|
51
|
+
signature,
|
|
52
|
+
matcher,
|
|
53
|
+
precedence,
|
|
54
|
+
};
|
|
55
|
+
delimiters[index] = delimiter;
|
|
56
|
+
stack.push(delimiter);
|
|
57
|
+
order.push(index);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
order.push(-1);
|
|
43
61
|
}
|
|
44
|
-
++this.length;
|
|
45
62
|
}
|
|
46
63
|
}
|
|
47
64
|
public pop(count = 1): void {
|
|
48
65
|
assert(count > 0);
|
|
66
|
+
const { registry, delimiters, order } = this;
|
|
49
67
|
for (let i = 0; i < count; ++i) {
|
|
50
|
-
assert(this.
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
68
|
+
assert(this.order.length > 0);
|
|
69
|
+
const index = order.pop()!;
|
|
70
|
+
if (index === -1) continue;
|
|
71
|
+
const stack = registry(delimiters[index].signature);
|
|
72
|
+
assert(stack.length > 0);
|
|
73
|
+
if (stack.length === 1) {
|
|
74
|
+
assert(index === delimiters.length - 1);
|
|
75
|
+
assert(stack[0] === delimiters.at(-1));
|
|
76
|
+
stack.pop();
|
|
77
|
+
delimiters.pop();
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
stack.pop();
|
|
81
|
+
delimiters[index] = stack.at(-1)!;
|
|
54
82
|
}
|
|
55
83
|
}
|
|
56
84
|
}
|
|
57
85
|
public match(source: string, precedence = 1): boolean {
|
|
58
|
-
const {
|
|
59
|
-
for (let i = 0; i <
|
|
60
|
-
const
|
|
61
|
-
if (precedence >=
|
|
62
|
-
switch (matcher
|
|
86
|
+
const { delimiters } = this;
|
|
87
|
+
for (let i = 0; i < delimiters.length; ++i) {
|
|
88
|
+
const delimiter = delimiters[i];
|
|
89
|
+
if (precedence >= delimiter.precedence) continue;
|
|
90
|
+
switch (delimiter.matcher(source)) {
|
|
63
91
|
case true:
|
|
64
92
|
return true;
|
|
65
93
|
case false:
|
|
@@ -3,7 +3,7 @@ export class Memo {
|
|
|
3
3
|
this.targets = targets;
|
|
4
4
|
}
|
|
5
5
|
public readonly targets: number;
|
|
6
|
-
private readonly memory: Record<
|
|
6
|
+
private readonly memory: Record<number, Record<number, readonly [any[], number] | readonly []>>[/* pos */] = [];
|
|
7
7
|
public get length(): number {
|
|
8
8
|
return this.memory.length;
|
|
9
9
|
}
|
|
@@ -12,8 +12,8 @@ export class Memo {
|
|
|
12
12
|
syntax: number,
|
|
13
13
|
state: number,
|
|
14
14
|
): readonly [any[], number] | readonly [] | undefined {
|
|
15
|
-
//console.log('get', position, syntax, state, this.memory[position - 1]?.[
|
|
16
|
-
const cache = this.memory[position - 1]?.[
|
|
15
|
+
//console.log('get', position, syntax, state, this.memory[position - 1]?.[syntax]?.[state]);
|
|
16
|
+
const cache = this.memory[position - 1]?.[syntax]?.[state];
|
|
17
17
|
return cache?.length === 2
|
|
18
18
|
? [cache[0].slice(), cache[1]]
|
|
19
19
|
: cache;
|
|
@@ -26,11 +26,11 @@ export class Memo {
|
|
|
26
26
|
offset: number,
|
|
27
27
|
): void {
|
|
28
28
|
const record = this.memory[position - 1] ??= {};
|
|
29
|
-
assert(!record[
|
|
30
|
-
record[
|
|
29
|
+
assert(!record[syntax]?.[state]);
|
|
30
|
+
(record[syntax] ??= {})[state] = nodes
|
|
31
31
|
? [nodes.slice(), offset]
|
|
32
32
|
: [];
|
|
33
|
-
//console.log('set', position, syntax, state, record[
|
|
33
|
+
//console.log('set', position, syntax, state, record[syntax]?.[state]);
|
|
34
34
|
}
|
|
35
35
|
public clear(position: number): void {
|
|
36
36
|
const memory = this.memory;
|
|
@@ -66,9 +66,9 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
|
|
|
66
66
|
return result;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number,
|
|
70
|
-
export function syntax<T>(syntax: number, prec: number,
|
|
71
|
-
return
|
|
69
|
+
export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number, state: number, parser: P): P;
|
|
70
|
+
export function syntax<T>(syntax: number, prec: number, state: number, parser?: Parser<T>): Parser<T> {
|
|
71
|
+
return precedence(prec, ({ source, context }) => {
|
|
72
72
|
if (source === '') return;
|
|
73
73
|
const memo = context.memo ??= new Memo();
|
|
74
74
|
context.offset ??= 0;
|
|
@@ -91,7 +91,7 @@ export function syntax<T>(syntax: number, prec: number, cost: number, state: num
|
|
|
91
91
|
}
|
|
92
92
|
context.state = stateOuter;
|
|
93
93
|
return result;
|
|
94
|
-
})
|
|
94
|
+
});
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export function creation<P extends Parser<unknown>>(parser: P): P;
|
|
@@ -100,11 +100,13 @@ export function creation<P extends Parser<unknown>>(cost: number, recursion: boo
|
|
|
100
100
|
export function creation(cost: number | Parser<unknown>, recursion?: boolean | Parser<unknown>, parser?: Parser<unknown>): Parser<unknown> {
|
|
101
101
|
if (typeof cost === 'function') return creation(1, true, cost);
|
|
102
102
|
if (typeof recursion === 'function') return creation(cost, true, recursion);
|
|
103
|
-
assert(cost
|
|
103
|
+
assert(cost >= 0);
|
|
104
|
+
assert(recursion !== undefined);
|
|
104
105
|
return ({ source, context }) => {
|
|
105
|
-
|
|
106
|
+
assert([recursion = recursion!]);
|
|
107
|
+
const resources = context.resources ?? { clock: cost || 1, recursion: 1 };
|
|
106
108
|
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
107
|
-
if (resources.recursion
|
|
109
|
+
if (resources.recursion < +recursion) throw new Error('Too much recursion');
|
|
108
110
|
recursion && --resources.recursion;
|
|
109
111
|
const result = parser!({ source, context });
|
|
110
112
|
recursion && ++resources.recursion;
|
|
@@ -171,3 +173,17 @@ export function state<T>(state: number, positive: boolean | Parser<T>, parser?:
|
|
|
171
173
|
return result;
|
|
172
174
|
};
|
|
173
175
|
}
|
|
176
|
+
|
|
177
|
+
//export function log<P extends Parser<unknown>>(log: number, parser: P, cond?: (ns: readonly Tree<P>[]) => boolean): P;
|
|
178
|
+
//export function log<T>(log: number, parser: Parser<T>, cond: (ns: readonly T[]) => boolean = () => true): Parser<T> {
|
|
179
|
+
// assert(log);
|
|
180
|
+
// return ({ source, context }) => {
|
|
181
|
+
// const l = context.log ?? 0;
|
|
182
|
+
// context.log = 0;
|
|
183
|
+
// const result = parser!({ source, context });
|
|
184
|
+
// context.log = result && cond(eval(result))
|
|
185
|
+
// ? l | log
|
|
186
|
+
// : l;
|
|
187
|
+
// return result;
|
|
188
|
+
// };
|
|
189
|
+
//}
|
|
@@ -298,17 +298,17 @@ describe('Unit: parser/api/parse', () => {
|
|
|
298
298
|
|
|
299
299
|
it('recursion', () => {
|
|
300
300
|
assert.deepStrictEqual(
|
|
301
|
-
[...parse('{'.repeat(
|
|
302
|
-
[`<p>${'{'.repeat(
|
|
301
|
+
[...parse('{'.repeat(21)).children].map(el => el.outerHTML),
|
|
302
|
+
[`<p>${'{'.repeat(21)}</p>`]);
|
|
303
303
|
assert.deepStrictEqual(
|
|
304
|
-
[...parse('{'.repeat(
|
|
304
|
+
[...parse('{'.repeat(22)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
305
305
|
[
|
|
306
306
|
'<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
|
|
307
|
-
`<pre class="error" translate="no">${'{'.repeat(
|
|
307
|
+
`<pre class="error" translate="no">${'{'.repeat(22)}</pre>`,
|
|
308
308
|
]);
|
|
309
309
|
assert.deepStrictEqual(
|
|
310
|
-
[...parse('('.repeat(
|
|
311
|
-
[`<p>${'('.repeat(
|
|
310
|
+
[...parse('('.repeat(21)).children].map(el => el.outerHTML),
|
|
311
|
+
[`<p>${'('.repeat(21)}</p>`]);
|
|
312
312
|
assert.deepStrictEqual(
|
|
313
313
|
[...parse('('.repeat(22)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
314
314
|
[
|
|
@@ -316,8 +316,8 @@ describe('Unit: parser/api/parse', () => {
|
|
|
316
316
|
`<pre class="error" translate="no">${'('.repeat(22)}</pre>`,
|
|
317
317
|
]);
|
|
318
318
|
assert.deepStrictEqual(
|
|
319
|
-
[...parse('['.repeat(
|
|
320
|
-
[`<p>${'['.repeat(
|
|
319
|
+
[...parse('['.repeat(21)).children].map(el => el.outerHTML),
|
|
320
|
+
[`<p>${'['.repeat(21)}</p>`]);
|
|
321
321
|
assert.deepStrictEqual(
|
|
322
322
|
[...parse('['.repeat(22)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
323
323
|
[
|
|
@@ -325,8 +325,8 @@ describe('Unit: parser/api/parse', () => {
|
|
|
325
325
|
`<pre class="error" translate="no">${'['.repeat(22)}</pre>`,
|
|
326
326
|
]);
|
|
327
327
|
assert.deepStrictEqual(
|
|
328
|
-
[...parse('['.repeat(
|
|
329
|
-
[`<p>${'['.repeat(
|
|
328
|
+
[...parse('['.repeat(20) + '\na').children].map(el => el.outerHTML),
|
|
329
|
+
[`<p>${'['.repeat(20)}<br>a</p>`]);
|
|
330
330
|
});
|
|
331
331
|
|
|
332
332
|
if (!navigator.userAgent.includes('Chrome')) return;
|
|
@@ -335,15 +335,15 @@ describe('Unit: parser/api/parse', () => {
|
|
|
335
335
|
this.timeout(5000);
|
|
336
336
|
// 実測500ms程度
|
|
337
337
|
assert.deepStrictEqual(
|
|
338
|
-
[...parse('.'.repeat(
|
|
339
|
-
[`<p>${'.'.repeat(
|
|
338
|
+
[...parse('.'.repeat(20000)).children].map(el => el.outerHTML),
|
|
339
|
+
[`<p>${'.'.repeat(20000)}</p>`]);
|
|
340
340
|
});
|
|
341
341
|
|
|
342
342
|
it('creation error', function () {
|
|
343
343
|
this.timeout(5000);
|
|
344
344
|
// 実測500ms程度
|
|
345
345
|
assert.deepStrictEqual(
|
|
346
|
-
[...parse('.'.repeat(
|
|
346
|
+
[...parse('.'.repeat(20001)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
347
347
|
[
|
|
348
348
|
'<h1 id="error:rnd" class="error">Error: Too many creations</h1>',
|
|
349
349
|
`<pre class="error" translate="no">${'.'.repeat(1000).slice(0, 997)}...</pre>`,
|
|
@@ -119,7 +119,7 @@ const dataline: CellParser.DatalineParser = creation(1, false, line(
|
|
|
119
119
|
convert(source => `: ${source}`, data),
|
|
120
120
|
]))));
|
|
121
121
|
|
|
122
|
-
function attributes(source: string) {
|
|
122
|
+
function attributes(source: string): Record<string, string | undefined> {
|
|
123
123
|
let [, rowspan = undefined, colspan = undefined, highlight = undefined, extension = undefined] =
|
|
124
124
|
source.match(/^[#:](?:(\d+)?:(\d+)?)?(?:(!+)([+]?))?$/) ?? [];
|
|
125
125
|
assert(rowspan?.[0] !== '0');
|
package/src/parser/block.ts
CHANGED
|
@@ -36,8 +36,8 @@ export import MediaBlockParser = BlockParser.MediaBlockParser;
|
|
|
36
36
|
export import ReplyParser = BlockParser.ReplyParser;
|
|
37
37
|
export import ParagraphParser = BlockParser.ParagraphParser;
|
|
38
38
|
|
|
39
|
-
export const block: BlockParser = creation(
|
|
40
|
-
reset({ resources: { clock:
|
|
39
|
+
export const block: BlockParser = creation(0, false, error(
|
|
40
|
+
reset({ resources: { clock: 20000, recursion: 20 + 1 } },
|
|
41
41
|
union([
|
|
42
42
|
emptyline,
|
|
43
43
|
pagebreak,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { AnnotationParser } from '../inline';
|
|
2
|
-
import { union, some, syntax, constraint, surround, lazy } from '../../combinator';
|
|
2
|
+
import { union, some, syntax, creation, constraint, surround, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { Syntax, State } from '../context';
|
|
5
5
|
import { trimBlankStart, trimNodeEnd } from '../visibility';
|
|
6
6
|
import { html, defrag } from 'typed-dom/dom';
|
|
7
7
|
|
|
8
|
-
export const annotation: AnnotationParser = lazy(() => surround(
|
|
8
|
+
export const annotation: AnnotationParser = lazy(() => creation(surround(
|
|
9
9
|
'((',
|
|
10
10
|
constraint(State.annotation, false,
|
|
11
|
-
syntax(Syntax.none, 6,
|
|
11
|
+
syntax(Syntax.none, 6, State.annotation | State.media,
|
|
12
12
|
trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 2], ['))', 6]])))),
|
|
13
13
|
'))',
|
|
14
14
|
false,
|
|
15
|
-
([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest]));
|
|
15
|
+
([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest])));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, tails, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
|
|
3
3
|
import { unsafelink } from '../link';
|
|
4
4
|
import { str } from '../../source';
|
|
5
5
|
import { State } from '../../context';
|
|
@@ -28,5 +28,5 @@ const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(prec
|
|
|
28
28
|
surround('(', some(union([bracket, unescsource]), ')'), ')', true),
|
|
29
29
|
surround('[', some(union([bracket, unescsource]), ']'), ']', true),
|
|
30
30
|
surround('{', some(union([bracket, unescsource]), '}'), '}', true),
|
|
31
|
-
surround('"', precedence(
|
|
31
|
+
surround('"', precedence(3, some(unescsource, '"')), '"', true),
|
|
32
32
|
]))));
|
|
@@ -12,9 +12,9 @@ import { Syntax, State } from '../context';
|
|
|
12
12
|
import { stringify } from '../util';
|
|
13
13
|
|
|
14
14
|
export const autolink: AutolinkParser = lazy(() =>
|
|
15
|
-
validate(/^(?:[@#>0-9a-z
|
|
15
|
+
validate(/^(?:[@#>0-9a-z]|\S[#>]|[\r\n]!?https?:\/\/)/iu,
|
|
16
16
|
constraint(State.autolink, false,
|
|
17
|
-
syntax(Syntax.autolink, 1,
|
|
17
|
+
syntax(Syntax.autolink, 1, ~State.shortcut,
|
|
18
18
|
union([
|
|
19
19
|
some(union([lineurl])),
|
|
20
20
|
fmap(some(union([
|
|
@@ -48,6 +48,9 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
48
48
|
assert.deepStrictEqual(inspect(parser('(A)')), [['(', 'A', ')'], '']);
|
|
49
49
|
assert.deepStrictEqual(inspect(parser('(A,B)')), [['(', 'A,B', ')'], '']);
|
|
50
50
|
assert.deepStrictEqual(inspect(parser('(A、B)')), [['(', 'A、B', ')'], '']);
|
|
51
|
+
assert.deepStrictEqual(inspect(parser('(<bdi>a\\\nb</bdi>)')), [['<span class="paren">(<bdi>a<br>b</bdi>)</span>'], '']);
|
|
52
|
+
assert.deepStrictEqual(inspect(parser('([% a\\\nb %])')), [['<span class="paren">(<span class="remark"><input type="checkbox"><span>[% a<br>b %]</span></span>)</span>'], '']);
|
|
53
|
+
assert.deepStrictEqual(inspect(parser('({{\\\n}})')), [['<span class="paren">(<span class="template">{{\\\n}}</span>)</span>'], '']);
|
|
51
54
|
});
|
|
52
55
|
|
|
53
56
|
it('[', () => {
|
|
@@ -77,8 +80,6 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
77
80
|
assert.deepStrictEqual(inspect(parser('"(")"')), [['"', '(', '"'], ')"']);
|
|
78
81
|
assert.deepStrictEqual(inspect(parser('"(("')), [['"', '(', '(', '"'], '']);
|
|
79
82
|
assert.deepStrictEqual(inspect(parser('"(\\")"')), [['"', '<span class="paren">(")</span>', '"'], '']);
|
|
80
|
-
assert.deepStrictEqual(inspect(parser('"(\n)"')), [['"', '<span class="paren">(<br>)</span>', '"'], '']);
|
|
81
|
-
assert.deepStrictEqual(inspect(parser('"(\\\n)"')), [['"', '<span class="paren">(<br>)</span>', '"'], '']);
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BracketParser } from '../inline';
|
|
2
|
-
import { union, some, syntax, surround, lazy } from '../../combinator';
|
|
2
|
+
import { union, some, syntax, creation, surround, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
5
|
import { Syntax, State } from '../context';
|
|
@@ -9,22 +9,21 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
9
9
|
const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
|
|
10
10
|
|
|
11
11
|
export const bracket: BracketParser = lazy(() => union([
|
|
12
|
-
surround(str('('), syntax(Syntax.none, 2,
|
|
13
|
-
surround(str('('), syntax(Syntax.bracket, 2,
|
|
12
|
+
surround(str('('), creation(syntax(Syntax.none, 2, State.none, str(index))), str(')')),
|
|
13
|
+
surround(str('('), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
|
|
14
14
|
([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
|
|
15
15
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
16
|
-
surround(str('('), syntax(Syntax.none, 2,
|
|
17
|
-
surround(str('('), syntax(Syntax.bracket, 2,
|
|
16
|
+
surround(str('('), creation(syntax(Syntax.none, 2, State.none, str(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))))), str(')')),
|
|
17
|
+
surround(str('('), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
|
|
18
18
|
([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
|
|
19
19
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
20
|
-
surround(str('['), syntax(Syntax.bracket, 2,
|
|
20
|
+
surround(str('['), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
|
|
21
21
|
undefined,
|
|
22
22
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
23
|
-
surround(str('{'), syntax(Syntax.bracket, 2,
|
|
23
|
+
surround(str('{'), creation(syntax(Syntax.bracket, 2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
|
|
24
24
|
undefined,
|
|
25
25
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
26
|
-
|
|
27
|
-
surround(str('"'), syntax(Syntax.none, 3, 1, State.none, some(inline, '"', [['"', 3]])), str('"'), true,
|
|
26
|
+
surround(str('"'), creation(syntax(Syntax.none, 3, State.none, some(inline, '"', [[/^\\?\n/, 4], ['"', 3]]))), str('"'), true,
|
|
28
27
|
undefined,
|
|
29
28
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
30
29
|
]));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DeletionParser } from '../inline';
|
|
2
|
-
import { union, some, syntax, surround, open, lazy } from '../../combinator';
|
|
2
|
+
import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
5
|
import { Syntax, State } from '../context';
|
|
@@ -7,13 +7,13 @@ import { blankWith } from '../visibility';
|
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
|
-
export const deletion: DeletionParser = lazy(() => surround(
|
|
10
|
+
export const deletion: DeletionParser = lazy(() => creation(surround(
|
|
11
11
|
str('~~', '~'),
|
|
12
|
-
syntax(Syntax.none, 1,
|
|
12
|
+
syntax(Syntax.none, 1, State.none,
|
|
13
13
|
some(union([
|
|
14
14
|
some(inline, blankWith('\n', '~~')),
|
|
15
15
|
open('\n', some(inline, '~'), true),
|
|
16
16
|
]))),
|
|
17
17
|
str('~~'), false,
|
|
18
18
|
([, bs], rest) => [[html('del', defrag(bs))], rest],
|
|
19
|
-
([as, bs], rest) => [unshift(as, bs), rest]));
|
|
19
|
+
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EmphasisParser } from '../inline';
|
|
2
|
-
import { union, some, syntax, surround, open, lazy } from '../../combinator';
|
|
2
|
+
import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { emstrong } from './emstrong';
|
|
5
5
|
import { strong } from './strong';
|
|
@@ -9,9 +9,9 @@ import { startTight, blankWith } from '../visibility';
|
|
|
9
9
|
import { unshift } from 'spica/array';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
|
-
export const emphasis: EmphasisParser = lazy(() => surround(
|
|
12
|
+
export const emphasis: EmphasisParser = lazy(() => creation(surround(
|
|
13
13
|
str('*', '*'),
|
|
14
|
-
syntax(Syntax.none, 1,
|
|
14
|
+
syntax(Syntax.none, 1, State.none,
|
|
15
15
|
startTight(some(union([
|
|
16
16
|
strong,
|
|
17
17
|
some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
|
|
@@ -23,4 +23,4 @@ export const emphasis: EmphasisParser = lazy(() => surround(
|
|
|
23
23
|
])))),
|
|
24
24
|
str('*'), false,
|
|
25
25
|
([, bs], rest) => [[html('em', defrag(bs))], rest],
|
|
26
|
-
([as, bs], rest) => [unshift(as, bs), rest]));
|
|
26
|
+
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
|
|
2
2
|
import { Result, IntermediateParser } from '../../combinator/data/parser';
|
|
3
|
-
import { union, syntax, some, surround, open, lazy, bind } from '../../combinator';
|
|
3
|
+
import { union, syntax, creation, some, surround, open, lazy, bind } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { strong } from './strong';
|
|
6
6
|
import { emphasis } from './emphasis';
|
|
@@ -27,9 +27,9 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
|
|
|
27
27
|
])),
|
|
28
28
|
])));
|
|
29
29
|
|
|
30
|
-
export const emstrong: EmStrongParser = lazy(() => surround(
|
|
30
|
+
export const emstrong: EmStrongParser = lazy(() => creation(surround(
|
|
31
31
|
str('***'),
|
|
32
|
-
syntax(Syntax.none, 1,
|
|
32
|
+
syntax(Syntax.none, 1, State.none,
|
|
33
33
|
startTight(some(union([
|
|
34
34
|
some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
|
|
35
35
|
open(some(inline, '*', [[/^\\?\n/, 9]]), inline),
|
|
@@ -59,4 +59,4 @@ export const emstrong: EmStrongParser = lazy(() => surround(
|
|
|
59
59
|
}
|
|
60
60
|
assert(false);
|
|
61
61
|
},
|
|
62
|
-
([as, bs], rest) => [unshift(as, bs), rest]));
|
|
62
|
+
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
@@ -20,6 +20,12 @@ describe('Unit: parser/inline/extension/index', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('[#\\]')), undefined);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('[#a')), undefined);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('[#*a\nb*]')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('[#(a\nb)]')), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('[#"a\nb"]')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('[#<bdi>a\nb</bdi>]')), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('[#[% a\nb %]]')), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser('[#{{ a\nb }}]')), undefined);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser('[#({{ a\nb }})]')), undefined);
|
|
23
29
|
assert.deepStrictEqual(inspect(parser('[#a\n|b]')), undefined);
|
|
24
30
|
assert.deepStrictEqual(inspect(parser('[#a|\n]')), undefined);
|
|
25
31
|
assert.deepStrictEqual(inspect(parser('[#a|\\\n]')), undefined);
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
-
import { union, some, syntax, creation, precedence, constraint, validate, surround, open, lazy, fmap } from '../../../combinator';
|
|
2
|
+
import { union, inits, some, syntax, creation, precedence, constraint, validate, surround, open, lazy, fmap } from '../../../combinator';
|
|
3
3
|
import { inline } from '../../inline';
|
|
4
4
|
import { indexee, identity } from './indexee';
|
|
5
|
-
import { txt, str
|
|
5
|
+
import { txt, str } from '../../source';
|
|
6
6
|
import { Syntax, State } from '../../context';
|
|
7
7
|
import { startTight, trimNodeEnd } from '../../visibility';
|
|
8
8
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
import IndexParser = ExtensionParser.IndexParser;
|
|
11
11
|
|
|
12
|
-
export const index: IndexParser = lazy(() => validate('[#', fmap(indexee(surround(
|
|
12
|
+
export const index: IndexParser = lazy(() => validate('[#', creation(fmap(indexee(surround(
|
|
13
13
|
'[#',
|
|
14
14
|
constraint(State.index, false,
|
|
15
|
-
syntax(Syntax.index, 2,
|
|
15
|
+
syntax(Syntax.index, 2, State.linkers | State.media,
|
|
16
16
|
startTight(
|
|
17
|
-
|
|
18
|
-
signature,
|
|
17
|
+
some(inits([
|
|
19
18
|
inline,
|
|
20
|
-
|
|
19
|
+
signature,
|
|
20
|
+
]), ']', [[/^\\?\n/, 9], [']', 2]])))),
|
|
21
21
|
']',
|
|
22
22
|
false,
|
|
23
23
|
([, ns], rest) => [[html('a', trimNodeEnd(defrag(ns)))], rest])),
|
|
@@ -28,18 +28,18 @@ export const index: IndexParser = lazy(() => validate('[#', fmap(indexee(surroun
|
|
|
28
28
|
class: 'index',
|
|
29
29
|
href: el.id ? `#${el.id}` : undefined,
|
|
30
30
|
}),
|
|
31
|
-
])));
|
|
31
|
+
]))));
|
|
32
32
|
|
|
33
|
-
export const signature: IndexParser.SignatureParser = lazy(() => creation(fmap(open(
|
|
33
|
+
export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(fmap(open(
|
|
34
34
|
'|',
|
|
35
35
|
startTight(some(union([bracket, txt]), ']'))),
|
|
36
36
|
ns => [
|
|
37
37
|
html('span', { class: 'indexer', 'data-index': identity(undefined, ns.join(''))!.slice(7) }),
|
|
38
|
-
])));
|
|
38
|
+
]))));
|
|
39
39
|
|
|
40
40
|
const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(union([
|
|
41
41
|
surround(str('('), some(union([bracket, txt]), ')'), str(')'), true),
|
|
42
42
|
surround(str('['), some(union([bracket, txt]), ']'), str(']'), true),
|
|
43
43
|
surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true),
|
|
44
|
-
surround(str('"'), precedence(
|
|
44
|
+
surround(str('"'), precedence(3, some(txt, '"')), str('"'), true),
|
|
45
45
|
])));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
-
import { union, some, syntax, validate, surround, lazy } from '../../../combinator';
|
|
2
|
+
import { union, some, syntax, creation, validate, surround, lazy } from '../../../combinator';
|
|
3
3
|
import { inline } from '../../inline';
|
|
4
4
|
import { str } from '../../source';
|
|
5
5
|
import { Syntax, State } from '../../context';
|
|
@@ -11,9 +11,9 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
11
11
|
|
|
12
12
|
// All syntax surrounded by square brackets shouldn't contain line breaks.
|
|
13
13
|
|
|
14
|
-
export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => validate('[', surround(
|
|
14
|
+
export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => validate('[', creation(surround(
|
|
15
15
|
str(/^\[[:^|]/),
|
|
16
|
-
syntax(Syntax.placeholder, 2,
|
|
16
|
+
syntax(Syntax.placeholder, 2, State.none,
|
|
17
17
|
startTight(some(union([inline]), ']', [[']', 2]]))),
|
|
18
18
|
str(']'), false,
|
|
19
19
|
([, bs], rest) => [[
|
|
@@ -24,4 +24,4 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => validat
|
|
|
24
24
|
'data-invalid-message': `Invalid start symbol or linebreak`,
|
|
25
25
|
}, defrag(bs)),
|
|
26
26
|
], rest],
|
|
27
|
-
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
27
|
+
([as, bs], rest) => [unshift(as, bs), rest]))));
|
|
@@ -75,7 +75,7 @@ describe('Unit: parser/inline/html', () => {
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it('nest', () => {
|
|
78
|
-
assert.deepStrictEqual(inspect(parser('<bdi>[% </bdi>')), [['<bdi
|
|
78
|
+
assert.deepStrictEqual(inspect(parser('<bdi>[% </bdi>')), [['<span class="invalid"><bdi>[% </bdi></span>'], '']);
|
|
79
79
|
assert.deepStrictEqual(inspect(parser('<bdi><bdi>a</bdi></bdi>')), [['<bdi><bdi>a</bdi></bdi>'], '']);
|
|
80
80
|
assert.deepStrictEqual(inspect(parser('<bdi>a<bdi>b</bdi>c</bdi>')), [['<bdi>a<bdi>b</bdi>c</bdi>'], '']);
|
|
81
81
|
assert.deepStrictEqual(inspect(parser('<bdi>`a`</bdi>')), [['<bdi><code data-src="`a`">a</code></bdi>'], '']);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HTMLParser } from '../inline';
|
|
2
|
-
import { union, subsequence, some, syntax, validate, focus, surround, open, match, lazy } from '../../combinator';
|
|
2
|
+
import { union, subsequence, some, syntax, creation, validate, focus, surround, open, match, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
5
|
import { Syntax, State } from '../context';
|
|
@@ -18,7 +18,7 @@ const attrspecs = {
|
|
|
18
18
|
Object.setPrototypeOf(attrspecs, null);
|
|
19
19
|
Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
|
|
20
20
|
|
|
21
|
-
export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, syntax(Syntax.none,
|
|
21
|
+
export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, creation(syntax(Syntax.none, 4, State.none, union([
|
|
22
22
|
focus(
|
|
23
23
|
/^<wbr[^\S\n]*>/i,
|
|
24
24
|
() => [[h('wbr')], '']),
|
|
@@ -35,7 +35,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
|
|
|
35
35
|
str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
|
|
36
36
|
subsequence([
|
|
37
37
|
focus(/^[^\S\n]*\n/, some(inline)),
|
|
38
|
-
some(open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`),
|
|
38
|
+
some(open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`), 4]]), true)),
|
|
39
39
|
]),
|
|
40
40
|
str(`</${tag}>`), true,
|
|
41
41
|
([as, bs = [], cs], rest) =>
|
|
@@ -50,7 +50,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
|
|
|
50
50
|
str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
|
|
51
51
|
subsequence([
|
|
52
52
|
focus(/^[^\S\n]*\n/, some(inline)),
|
|
53
|
-
some(inline, `</${tag}>`, [[`</${tag}>`,
|
|
53
|
+
some(inline, `</${tag}>`, [[`</${tag}>`, 4]]),
|
|
54
54
|
]),
|
|
55
55
|
str(`</${tag}>`), true,
|
|
56
56
|
([as, bs = [], cs], rest) =>
|
|
@@ -59,7 +59,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
|
|
|
59
59
|
[[elem(tag, as, bs, [])], rest]),
|
|
60
60
|
([, tag]) => tag,
|
|
61
61
|
new Clock(10000))),
|
|
62
|
-
])))));
|
|
62
|
+
]))))));
|
|
63
63
|
|
|
64
64
|
export const attribute: HTMLParser.AttributeParser = union([
|
|
65
65
|
str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="[^"\n]*")?(?=[^\S\n]|>)/i),
|