securemark 0.234.1 → 0.235.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 +12 -0
- package/dist/securemark.js +128 -136
- package/markdown.d.ts +4 -16
- package/package-lock.json +46 -43
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.ts +0 -2
- package/src/combinator/control/constraint/contract.ts +1 -1
- package/src/combinator/control/manipulation/context.ts +7 -0
- package/src/combinator/control/manipulation/match.ts +1 -1
- package/src/combinator/control/manipulation/scope.ts +1 -1
- package/src/combinator/data/parser/inits.ts +1 -1
- package/src/combinator/data/parser/sequence.ts +1 -1
- package/src/combinator/data/parser/some.ts +40 -18
- package/src/combinator/data/parser.ts +4 -1
- package/src/parser/api/normalize.ts +7 -6
- package/src/parser/block/heading.test.ts +1 -1
- package/src/parser/block/paragraph.test.ts +2 -0
- package/src/parser/inline/emphasis.test.ts +7 -4
- package/src/parser/inline/emphasis.ts +7 -7
- package/src/parser/inline/emstrong.ts +19 -18
- package/src/parser/inline/extension/index.test.ts +19 -18
- package/src/parser/inline/extension/index.ts +3 -4
- package/src/parser/inline/extension/indexer.test.ts +1 -0
- package/src/parser/inline/extension/indexer.ts +1 -0
- package/src/parser/inline/html.ts +4 -8
- package/src/parser/inline/htmlentity.test.ts +1 -0
- package/src/parser/inline/htmlentity.ts +9 -12
- package/src/parser/inline/link.ts +3 -4
- package/src/parser/inline/mark.test.ts +6 -3
- package/src/parser/inline/mark.ts +4 -4
- package/src/parser/inline/media.ts +8 -5
- package/src/parser/inline/ruby.ts +3 -4
- package/src/parser/inline/strong.test.ts +6 -4
- package/src/parser/inline/strong.ts +7 -7
- package/src/parser/inline.test.ts +15 -5
- package/src/parser/util.ts +11 -42
package/package-lock.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.235.0",
|
|
4
4
|
"lockfileVersion": 1,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"dependencies": {
|
|
@@ -449,9 +449,9 @@
|
|
|
449
449
|
},
|
|
450
450
|
"dependencies": {
|
|
451
451
|
"lru-cache": {
|
|
452
|
-
"version": "7.7.
|
|
453
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.
|
|
454
|
-
"integrity": "sha512-
|
|
452
|
+
"version": "7.7.2",
|
|
453
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
|
|
454
|
+
"integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
|
|
455
455
|
"dev": true
|
|
456
456
|
},
|
|
457
457
|
"mkdirp": {
|
|
@@ -1760,10 +1760,13 @@
|
|
|
1760
1760
|
"dev": true
|
|
1761
1761
|
},
|
|
1762
1762
|
"builtins": {
|
|
1763
|
-
"version": "
|
|
1764
|
-
"resolved": "https://registry.npmjs.org/builtins/-/builtins-
|
|
1765
|
-
"integrity": "
|
|
1766
|
-
"dev": true
|
|
1763
|
+
"version": "5.0.0",
|
|
1764
|
+
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.0.tgz",
|
|
1765
|
+
"integrity": "sha512-aizhtbxgT1Udg0Fj6GssXshAVK+nxbtCV+1OtTrMNy67jffDFBY6CUBAkhO4owbleAx6fdbnWdpsmmcXydbzNw==",
|
|
1766
|
+
"dev": true,
|
|
1767
|
+
"requires": {
|
|
1768
|
+
"semver": "^7.0.0"
|
|
1769
|
+
}
|
|
1767
1770
|
},
|
|
1768
1771
|
"bytes": {
|
|
1769
1772
|
"version": "3.1.2",
|
|
@@ -1798,9 +1801,9 @@
|
|
|
1798
1801
|
},
|
|
1799
1802
|
"dependencies": {
|
|
1800
1803
|
"lru-cache": {
|
|
1801
|
-
"version": "7.7.
|
|
1802
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.
|
|
1803
|
-
"integrity": "sha512-
|
|
1804
|
+
"version": "7.7.2",
|
|
1805
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
|
|
1806
|
+
"integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
|
|
1804
1807
|
"dev": true
|
|
1805
1808
|
},
|
|
1806
1809
|
"mkdirp": {
|
|
@@ -1924,9 +1927,9 @@
|
|
|
1924
1927
|
"dev": true
|
|
1925
1928
|
},
|
|
1926
1929
|
"caniuse-lite": {
|
|
1927
|
-
"version": "1.0.
|
|
1928
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
|
1929
|
-
"integrity": "sha512-
|
|
1930
|
+
"version": "1.0.30001322",
|
|
1931
|
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz",
|
|
1932
|
+
"integrity": "sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew==",
|
|
1930
1933
|
"dev": true
|
|
1931
1934
|
},
|
|
1932
1935
|
"chalk": {
|
|
@@ -3030,9 +3033,9 @@
|
|
|
3030
3033
|
"dev": true
|
|
3031
3034
|
},
|
|
3032
3035
|
"electron-to-chromium": {
|
|
3033
|
-
"version": "1.4.
|
|
3034
|
-
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.
|
|
3035
|
-
"integrity": "sha512-
|
|
3036
|
+
"version": "1.4.100",
|
|
3037
|
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.100.tgz",
|
|
3038
|
+
"integrity": "sha512-pNrSE2naf8fizl6/Uxq8UbKb8hU9EiYW4OzCYswosXoLV5NTMOUVKECNzDaHiUubsPq/kAckOzZd7zd8S8CHVw==",
|
|
3036
3039
|
"dev": true
|
|
3037
3040
|
},
|
|
3038
3041
|
"elliptic": {
|
|
@@ -4608,9 +4611,9 @@
|
|
|
4608
4611
|
"dev": true
|
|
4609
4612
|
},
|
|
4610
4613
|
"gauge": {
|
|
4611
|
-
"version": "4.0.
|
|
4612
|
-
"resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.
|
|
4613
|
-
"integrity": "sha512-
|
|
4614
|
+
"version": "4.0.4",
|
|
4615
|
+
"resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
|
|
4616
|
+
"integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
|
|
4614
4617
|
"dev": true,
|
|
4615
4618
|
"requires": {
|
|
4616
4619
|
"aproba": "^1.0.3 || ^2.0.0",
|
|
@@ -7092,9 +7095,9 @@
|
|
|
7092
7095
|
}
|
|
7093
7096
|
},
|
|
7094
7097
|
"make-fetch-happen": {
|
|
7095
|
-
"version": "10.1.
|
|
7096
|
-
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.
|
|
7097
|
-
"integrity": "sha512-
|
|
7098
|
+
"version": "10.1.1",
|
|
7099
|
+
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.1.tgz",
|
|
7100
|
+
"integrity": "sha512-3/mCljDQNjmrP7kl0vhS5WVlV+TvSKoZaFhdiYV7MOijEnrhrjaVnqbp/EY/7S+fhUB2KpH7j8c1iRsIOs+kjw==",
|
|
7098
7101
|
"dev": true,
|
|
7099
7102
|
"requires": {
|
|
7100
7103
|
"agentkeepalive": "^4.2.1",
|
|
@@ -7116,9 +7119,9 @@
|
|
|
7116
7119
|
},
|
|
7117
7120
|
"dependencies": {
|
|
7118
7121
|
"lru-cache": {
|
|
7119
|
-
"version": "7.7.
|
|
7120
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.
|
|
7121
|
-
"integrity": "sha512-
|
|
7122
|
+
"version": "7.7.2",
|
|
7123
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
|
|
7124
|
+
"integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
|
|
7122
7125
|
"dev": true
|
|
7123
7126
|
}
|
|
7124
7127
|
}
|
|
@@ -8128,14 +8131,14 @@
|
|
|
8128
8131
|
"dev": true
|
|
8129
8132
|
},
|
|
8130
8133
|
"npm-package-arg": {
|
|
8131
|
-
"version": "9.0.
|
|
8132
|
-
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.
|
|
8133
|
-
"integrity": "sha512-
|
|
8134
|
+
"version": "9.0.2",
|
|
8135
|
+
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.2.tgz",
|
|
8136
|
+
"integrity": "sha512-v/miORuX8cndiOheW8p2moNuPJ7QhcFh9WGlTorruG8hXSA23vMTEp5hTCmDxic0nD8KHhj/NQgFuySD3GYY3g==",
|
|
8134
8137
|
"dev": true,
|
|
8135
8138
|
"requires": {
|
|
8136
8139
|
"hosted-git-info": "^5.0.0",
|
|
8137
8140
|
"semver": "^7.3.5",
|
|
8138
|
-
"validate-npm-package-name": "^
|
|
8141
|
+
"validate-npm-package-name": "^4.0.0"
|
|
8139
8142
|
},
|
|
8140
8143
|
"dependencies": {
|
|
8141
8144
|
"hosted-git-info": {
|
|
@@ -8148,9 +8151,9 @@
|
|
|
8148
8151
|
}
|
|
8149
8152
|
},
|
|
8150
8153
|
"lru-cache": {
|
|
8151
|
-
"version": "7.7.
|
|
8152
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.
|
|
8153
|
-
"integrity": "sha512-
|
|
8154
|
+
"version": "7.7.2",
|
|
8155
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
|
|
8156
|
+
"integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
|
|
8154
8157
|
"dev": true
|
|
8155
8158
|
}
|
|
8156
8159
|
}
|
|
@@ -8918,9 +8921,9 @@
|
|
|
8918
8921
|
"dev": true
|
|
8919
8922
|
},
|
|
8920
8923
|
"proc-log": {
|
|
8921
|
-
"version": "2.0.
|
|
8922
|
-
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.
|
|
8923
|
-
"integrity": "sha512-
|
|
8924
|
+
"version": "2.0.1",
|
|
8925
|
+
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
|
|
8926
|
+
"integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==",
|
|
8924
8927
|
"dev": true
|
|
8925
8928
|
},
|
|
8926
8929
|
"process": {
|
|
@@ -9187,9 +9190,9 @@
|
|
|
9187
9190
|
}
|
|
9188
9191
|
},
|
|
9189
9192
|
"lru-cache": {
|
|
9190
|
-
"version": "7.7.
|
|
9191
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.
|
|
9192
|
-
"integrity": "sha512-
|
|
9193
|
+
"version": "7.7.2",
|
|
9194
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
|
|
9195
|
+
"integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
|
|
9193
9196
|
"dev": true
|
|
9194
9197
|
},
|
|
9195
9198
|
"normalize-package-data": {
|
|
@@ -11307,12 +11310,12 @@
|
|
|
11307
11310
|
}
|
|
11308
11311
|
},
|
|
11309
11312
|
"validate-npm-package-name": {
|
|
11310
|
-
"version": "
|
|
11311
|
-
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-
|
|
11312
|
-
"integrity": "
|
|
11313
|
+
"version": "4.0.0",
|
|
11314
|
+
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz",
|
|
11315
|
+
"integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==",
|
|
11313
11316
|
"dev": true,
|
|
11314
11317
|
"requires": {
|
|
11315
|
-
"builtins": "^
|
|
11318
|
+
"builtins": "^5.0.0"
|
|
11316
11319
|
}
|
|
11317
11320
|
},
|
|
11318
11321
|
"value-or-function": {
|
package/package.json
CHANGED
|
@@ -6,10 +6,8 @@ export function block<P extends Parser<unknown>>(parser: P, separation?: boolean
|
|
|
6
6
|
export function block<T>(parser: Parser<T>, separation = true): Parser<T> {
|
|
7
7
|
assert(parser);
|
|
8
8
|
return (source, context) => {
|
|
9
|
-
assert(!context?.delimiters);
|
|
10
9
|
if (source === '') return;
|
|
11
10
|
const result = parser(source, context);
|
|
12
|
-
assert(!context?.delimiters);
|
|
13
11
|
if (!result) return;
|
|
14
12
|
const rest = exec(result);
|
|
15
13
|
if (separation && !isEmpty(firstline(rest))) return;
|
|
@@ -15,7 +15,7 @@ export function validate<T>(patterns: string | RegExp | (string | RegExp)[], has
|
|
|
15
15
|
if (typeof end === 'function') return validate(patterns, has, '', end);
|
|
16
16
|
if (!isArray(patterns)) return validate([patterns], has, end!, parser!);
|
|
17
17
|
assert(patterns.length > 0);
|
|
18
|
-
assert(patterns.every(pattern => pattern instanceof RegExp ? !pattern.
|
|
18
|
+
assert(patterns.every(pattern => pattern instanceof RegExp ? !pattern.flags.match(/[gmy]/) && pattern.source.startsWith('^') : true));
|
|
19
19
|
assert(parser);
|
|
20
20
|
const match: (source: string) => boolean = Function([
|
|
21
21
|
'"use strict";',
|
|
@@ -17,6 +17,7 @@ export function reset<P extends Parser<unknown>>(context: Context<P>, parser: P)
|
|
|
17
17
|
export function reset<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
18
18
|
assert(Object.getPrototypeOf(base) === Object.prototype);
|
|
19
19
|
assert(Object.freeze(base));
|
|
20
|
+
if (isEmpty(base)) return parser;
|
|
20
21
|
return (source, context) =>
|
|
21
22
|
parser(source, inherit(ObjectCreate(context), base));
|
|
22
23
|
}
|
|
@@ -25,6 +26,7 @@ export function context<P extends Parser<unknown>>(context: Context<P>, parser:
|
|
|
25
26
|
export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
26
27
|
assert(Object.getPrototypeOf(base) === Object.prototype);
|
|
27
28
|
assert(Object.freeze(base));
|
|
29
|
+
if (isEmpty(base)) return parser;
|
|
28
30
|
const override = memoize<Ctx, Ctx>(context => inherit(ObjectCreate(context), base), new WeakMap());
|
|
29
31
|
return (source, context) =>
|
|
30
32
|
parser(source, override(context));
|
|
@@ -56,3 +58,8 @@ const inherit = template((prop, target, source) => {
|
|
|
56
58
|
return target[prop] = source[prop];
|
|
57
59
|
}
|
|
58
60
|
});
|
|
61
|
+
|
|
62
|
+
function isEmpty(context: Ctx): boolean {
|
|
63
|
+
for (const _ in context) return false;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Parser, exec, check } from '../../data/parser';
|
|
|
3
3
|
|
|
4
4
|
export function match<P extends Parser<unknown>>(pattern: RegExp, f: (matched: RegExpMatchArray) => P): P;
|
|
5
5
|
export function match<T>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<T>): Parser<T> {
|
|
6
|
-
assert(!pattern.
|
|
6
|
+
assert(!pattern.flags.match(/[gmy]/) && pattern.source.startsWith('^'));
|
|
7
7
|
return (source, context) => {
|
|
8
8
|
if (source === '') return;
|
|
9
9
|
const param = source.match(pattern);
|
|
@@ -3,7 +3,7 @@ import { Parser, Context, eval, exec, check } from '../../data/parser';
|
|
|
3
3
|
|
|
4
4
|
export function focus<P extends Parser<unknown>>(scope: string | RegExp, parser: P): P;
|
|
5
5
|
export function focus<T>(scope: string | RegExp, parser: Parser<T>): Parser<T> {
|
|
6
|
-
assert(scope instanceof RegExp ? !scope.
|
|
6
|
+
assert(scope instanceof RegExp ? !scope.flags.match(/[gmy]/) && scope.source.startsWith('^') : scope);
|
|
7
7
|
assert(parser);
|
|
8
8
|
const match: (source: string) => string = typeof scope === 'string'
|
|
9
9
|
? source => source.slice(0, scope.length) === scope ? scope : ''
|
|
@@ -14,7 +14,7 @@ export function inits<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
|
14
14
|
const result = parsers[i](rest, context);
|
|
15
15
|
assert(check(rest, result));
|
|
16
16
|
if (!result) break;
|
|
17
|
-
assert(!context?.delimiters?.some(
|
|
17
|
+
assert(!context?.delimiters?.stack.some(sig => context.delimiters!.matchers[sig](rest)));
|
|
18
18
|
nodes = nodes
|
|
19
19
|
? push(nodes, eval(result))
|
|
20
20
|
: eval(result);
|
|
@@ -14,7 +14,7 @@ export function sequence<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D
|
|
|
14
14
|
const result = parsers[i](rest, context);
|
|
15
15
|
assert(check(rest, result));
|
|
16
16
|
if (!result) return;
|
|
17
|
-
assert(!context?.delimiters?.some(
|
|
17
|
+
assert(!context?.delimiters?.stack.some(sig => context.delimiters!.matchers[sig](rest)));
|
|
18
18
|
nodes = nodes
|
|
19
19
|
? push(nodes, eval(result))
|
|
20
20
|
: eval(result);
|
|
@@ -1,33 +1,58 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { Parser, eval, exec, check } from '../parser';
|
|
3
|
+
import { memoize, reduce } from 'spica/memoize';
|
|
3
4
|
import { push } from 'spica/array';
|
|
4
5
|
|
|
6
|
+
const signature = (pattern: string | RegExp | undefined): string => {
|
|
7
|
+
switch (typeof pattern) {
|
|
8
|
+
case 'undefined':
|
|
9
|
+
return signature('');
|
|
10
|
+
case 'string':
|
|
11
|
+
return `s:${pattern}`;
|
|
12
|
+
case 'object':
|
|
13
|
+
return `r/${pattern.source}/${pattern.flags}`;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const [matcher, delimiter] = [...Array(2)].map(() =>
|
|
17
|
+
memoize(
|
|
18
|
+
(pattern: string | RegExp | undefined): (source: string) => boolean => {
|
|
19
|
+
switch (typeof pattern) {
|
|
20
|
+
case 'undefined':
|
|
21
|
+
return () => false;
|
|
22
|
+
case 'string':
|
|
23
|
+
return source => source.slice(0, pattern.length) === pattern;
|
|
24
|
+
case 'object':
|
|
25
|
+
return reduce(source => pattern.test(source));
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
signature));
|
|
29
|
+
|
|
5
30
|
export function some<P extends Parser<unknown>>(parser: P, until?: string | RegExp | number, deep?: string | RegExp, limit?: number): P;
|
|
6
31
|
export function some<T>(parser: Parser<T>, until?: string | RegExp | number, deep?: string | RegExp, limit = -1): Parser<T> {
|
|
7
32
|
assert(parser);
|
|
8
|
-
assert(until instanceof RegExp ? !until.
|
|
33
|
+
assert(until instanceof RegExp ? !until.flags.match(/[gmy]/) && until.source.startsWith('^') : true);
|
|
34
|
+
assert(deep instanceof RegExp ? !deep.flags.match(/[gmy]/) && deep.source.startsWith('^') : true);
|
|
9
35
|
if (typeof until === 'number') return some(parser, undefined, deep, until);
|
|
10
|
-
const match
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const delim: (source: string) => boolean = typeof deep === 'string' && deep !== undefined
|
|
14
|
-
? source => source.slice(0, deep.length) === deep
|
|
15
|
-
: source => !!deep && deep.test(source);
|
|
16
|
-
let memory = '';
|
|
36
|
+
const match = matcher(until);
|
|
37
|
+
const delim = delimiter(deep);
|
|
38
|
+
const sig = signature(deep);
|
|
17
39
|
return (source, context) => {
|
|
18
|
-
if (source ===
|
|
40
|
+
if (source === '') return;
|
|
19
41
|
let rest = source;
|
|
20
42
|
let nodes: T[] | undefined;
|
|
21
43
|
if (context && deep) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
// bracket > annotation > bracket > reference > bracket > link > media | bracket
|
|
45
|
+
// bracket > annotation > bracket > reference > bracket > index > bracket
|
|
46
|
+
context.delimiters ??= { stack: [], matchers: {} };
|
|
47
|
+
context.delimiters.stack.push(sig);
|
|
48
|
+
context.delimiters.matchers[sig] ??= delim;
|
|
49
|
+
assert(context.delimiters.matchers[sig] === delim);
|
|
26
50
|
}
|
|
51
|
+
const { stack, matchers } = context.delimiters ?? {};
|
|
27
52
|
while (true) {
|
|
28
53
|
if (rest === '') break;
|
|
29
54
|
if (match(rest)) break;
|
|
30
|
-
if (
|
|
55
|
+
if (stack?.some(sig => matchers)) break;
|
|
31
56
|
const result = parser(rest, context);
|
|
32
57
|
assert.doesNotThrow(() => limit < 0 && check(rest, result));
|
|
33
58
|
if (!result) break;
|
|
@@ -38,11 +63,8 @@ export function some<T>(parser: Parser<T>, until?: string | RegExp | number, dee
|
|
|
38
63
|
if (limit >= 0 && source.length - rest.length > limit) break;
|
|
39
64
|
}
|
|
40
65
|
if (context && deep) {
|
|
41
|
-
|
|
42
|
-
? context.delimiters?.pop()
|
|
43
|
-
: context.delimiters = undefined;
|
|
66
|
+
stack?.pop();
|
|
44
67
|
}
|
|
45
|
-
memory = limit < 0 && rest || memory;
|
|
46
68
|
assert(rest.length <= source.length);
|
|
47
69
|
return nodes && rest.length < source.length
|
|
48
70
|
? [nodes, rest]
|
|
@@ -2,7 +2,10 @@ export interface Ctx {
|
|
|
2
2
|
readonly resources?: {
|
|
3
3
|
budget: number;
|
|
4
4
|
};
|
|
5
|
-
delimiters?:
|
|
5
|
+
delimiters?: {
|
|
6
|
+
readonly stack: string[];
|
|
7
|
+
readonly matchers: Record<string, (source: string) => boolean>;
|
|
8
|
+
};
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
export type Parser<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { eval } from '../../combinator/data/parser';
|
|
2
|
-
import {
|
|
3
|
-
import { stringify } from '../util';
|
|
2
|
+
import { unsafehtmlentity } from '../inline/htmlentity';
|
|
4
3
|
|
|
5
4
|
const UNICODE_REPLACEMENT_CHARACTER = '\uFFFD';
|
|
6
5
|
assert(UNICODE_REPLACEMENT_CHARACTER.trim());
|
|
@@ -25,9 +24,9 @@ function sanitize(source: string): string {
|
|
|
25
24
|
|
|
26
25
|
// https://dev.w3.org/html5/html-author/charref
|
|
27
26
|
// https://en.wikipedia.org/wiki/Whitespace_character
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
export const invisibleHTMLEntityNames = [
|
|
28
|
+
'Tab',
|
|
29
|
+
'NewLine',
|
|
31
30
|
'NonBreakingSpace',
|
|
32
31
|
'nbsp',
|
|
33
32
|
'shy',
|
|
@@ -59,8 +58,10 @@ const unreadableHTMLEntityNames = [
|
|
|
59
58
|
'InvisibleComma',
|
|
60
59
|
'ic',
|
|
61
60
|
] as const;
|
|
61
|
+
const unreadableHTMLEntityNames: readonly string[] = invisibleHTMLEntityNames.slice(2);
|
|
62
62
|
const unreadableEscapableCharacters = unreadableHTMLEntityNames
|
|
63
|
-
.map(name =>
|
|
63
|
+
.map(name => eval(unsafehtmlentity(`&${name};`, {}))![0]);
|
|
64
|
+
assert(unreadableEscapableCharacters.length === unreadableHTMLEntityNames.length);
|
|
64
65
|
assert(unreadableEscapableCharacters.every(c => c.length === 1));
|
|
65
66
|
const unreadableEscapableCharacter = new RegExp(`[${
|
|
66
67
|
[...new Set<string>(unreadableEscapableCharacters)].join('')
|
|
@@ -74,7 +74,7 @@ describe('Unit: parser/block/heading', () => {
|
|
|
74
74
|
assert.deepStrictEqual(inspect(parser('# a [#!http://host]')), [['<h1 id="index:!http://host">a<span class="indexer" data-index="!http://host"></span></h1>'], '']);
|
|
75
75
|
assert.deepStrictEqual(inspect(parser('# a [#a((b))]')), [['<h1 id="index:a((b))">a<span class="indexer" data-index="a((b))"></span></h1>'], '']);
|
|
76
76
|
assert.deepStrictEqual(inspect(parser('# a [#a[[b]]]')), [['<h1 id="index:a[[b]]">a<span class="indexer" data-index="a[[b]]"></span></h1>'], '']);
|
|
77
|
-
assert.deepStrictEqual(inspect(parser('# a [#b|#c]')), [['<h1 id="index:c">a<span class="indexer" data-index="c"></span></h1>'], '']);
|
|
77
|
+
assert.deepStrictEqual(inspect(parser('# a [#b |#c]')), [['<h1 id="index:c">a<span class="indexer" data-index="c"></span></h1>'], '']);
|
|
78
78
|
assert.deepStrictEqual(inspect(parser('# a [#b] [#c]')), [['<h1 id="index:c">a [#b]<span class="indexer" data-index="c"></span></h1>'], '']);
|
|
79
79
|
assert.deepStrictEqual(inspect(parser('# a [#b] \n')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
|
|
80
80
|
assert.deepStrictEqual(inspect(parser('# a \\[#b]')), [['<h1 id="index:a_[#b]">a [#b]</h1>'], '']);
|
|
@@ -20,6 +20,8 @@ describe('Unit: parser/block/paragraph', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('a\\ \n')), [['<p>a</p>'], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('a\\\n')), [['<p>a</p>'], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('a\\\nb')), [['<p>a<span class="linebreak"> </span>b</p>'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('a
b')), [['<p>a&NewLine;b</p>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('	
')), [['<p>&Tab;&NewLine;</p>'], '']);
|
|
23
25
|
assert.deepStrictEqual(inspect(parser('<wbr>')), [['<p><wbr></p>'], '']);
|
|
24
26
|
assert.deepStrictEqual(inspect(parser('<wbr>\n')), [['<p><wbr></p>'], '']);
|
|
25
27
|
assert.deepStrictEqual(inspect(parser('<wbr>\na')), [['<p><wbr><br>a</p>'], '']);
|
|
@@ -11,8 +11,8 @@ describe('Unit: parser/inline/emphasis', () => {
|
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('*a')), [['*', 'a'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a', ' ', '*'], '']);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('*a\n*')), [['*', 'a', '<br>', '*'], '']);
|
|
14
|
-
assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a', ' '
|
|
15
|
-
assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a', '<span class="linebreak"> </span>'
|
|
14
|
+
assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a', ' ', '*'], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a', '<span class="linebreak"> </span>', '*'], '']);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('*a**b')), [['*', 'a', '**', 'b'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('*a**b*')), [['*', 'a', '**', 'b', '*'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('* *')), undefined);
|
|
@@ -37,10 +37,13 @@ describe('Unit: parser/inline/emphasis', () => {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('nest', () => {
|
|
40
|
-
assert.deepStrictEqual(inspect(parser('*a**b**c*')), [['<em>a<strong>b</strong>c</em>'], '']);
|
|
41
|
-
assert.deepStrictEqual(inspect(parser('*a**b**c*d')), [['<em>a<strong>b</strong>c</em>'], 'd']);
|
|
42
40
|
assert.deepStrictEqual(inspect(parser('*a *b**')), [['<em>a <em>b</em></em>'], '']);
|
|
43
41
|
assert.deepStrictEqual(inspect(parser('*a **b***')), [['<em>a <strong>b</strong></em>'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('*a\\ *b**')), [['<em>a <em>b</em></em>'], '']);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('*a	*b**')), [['<em>a\t<em>b</em></em>'], '']);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('*a<wbr>*b**')), [['<em>a<wbr><em>b</em></em>'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser('*a**b**c*')), [['<em>a<strong>b</strong>c</em>'], '']);
|
|
46
|
+
assert.deepStrictEqual(inspect(parser('*a**b**c*d')), [['<em>a<strong>b</strong>c</em>'], 'd']);
|
|
44
47
|
assert.deepStrictEqual(inspect(parser('*`a`*')), [['<em><code data-src="`a`">a</code></em>'], '']);
|
|
45
48
|
assert.deepStrictEqual(inspect(parser('*<small>*')), [['<em><small></em>'], '']);
|
|
46
49
|
assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { EmphasisParser } from '../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, some, creator, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { strong } from './strong';
|
|
5
5
|
import { str } from '../source';
|
|
6
|
-
import { startTight, isEndTightNodes } from '../util';
|
|
6
|
+
import { startTight, isEndTightNodes, delimiter } from '../util';
|
|
7
7
|
import { html, defrag } from 'typed-dom';
|
|
8
8
|
import { unshift } from 'spica/array';
|
|
9
9
|
|
|
10
|
-
export const emphasis: EmphasisParser = lazy(() => creator(surround(
|
|
11
|
-
str('*'),
|
|
10
|
+
export const emphasis: EmphasisParser = lazy(() => creator(surround(
|
|
11
|
+
str('*'),
|
|
12
12
|
startTight(some(union([
|
|
13
13
|
strong,
|
|
14
|
-
some(inline,
|
|
15
|
-
|
|
16
|
-
]))),
|
|
14
|
+
some(inline, delimiter(/\*/)),
|
|
15
|
+
open(some(inline, '*'), inline),
|
|
16
|
+
])), '*'),
|
|
17
17
|
str('*'), false,
|
|
18
18
|
([as, bs, cs], rest) =>
|
|
19
19
|
isEndTightNodes(bs)
|
|
@@ -1,42 +1,37 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../../markdown';
|
|
2
2
|
import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
|
|
3
3
|
import { Result, IntermediateParser } from '../../combinator/data/parser';
|
|
4
|
-
import { union,
|
|
4
|
+
import { union, some, creator, surround, open, lazy, bind } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { strong } from './strong';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import { startTight, isEndTightNodes } from '../util';
|
|
8
|
+
import { startTight, isEndTightNodes, delimiter } from '../util';
|
|
9
9
|
import { html, defrag } from 'typed-dom';
|
|
10
10
|
import { unshift } from 'spica/array';
|
|
11
11
|
|
|
12
12
|
const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
|
|
13
|
-
some(inline,
|
|
14
|
-
|
|
13
|
+
some(inline, delimiter(/\*\*/)),
|
|
14
|
+
open(some(inline, '*'), inline),
|
|
15
15
|
])));
|
|
16
16
|
const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
|
|
17
17
|
strong,
|
|
18
|
-
some(inline,
|
|
19
|
-
|
|
18
|
+
some(inline, delimiter(/\*/)),
|
|
19
|
+
open(some(inline, '*'), inline),
|
|
20
20
|
])));
|
|
21
21
|
|
|
22
22
|
export const emstrong: EmStrongParser = lazy(() => creator(surround(
|
|
23
23
|
str('***'),
|
|
24
24
|
startTight(some(union([
|
|
25
|
-
some(inline,
|
|
26
|
-
|
|
25
|
+
some(inline, delimiter(/\*/)),
|
|
26
|
+
open(some(inline, '*'), inline),
|
|
27
27
|
]))),
|
|
28
28
|
str(/^\*{1,3}/), false,
|
|
29
29
|
([as, bs, cs], rest, context): Result<HTMLElement | string, MarkdownParser.Context> => {
|
|
30
|
+
assert(cs.length === 1);
|
|
30
31
|
if (!isEndTightNodes(bs)) return [unshift(as, bs), cs[0] + rest];
|
|
31
32
|
switch (cs[0]) {
|
|
32
|
-
case '
|
|
33
|
-
return
|
|
34
|
-
substrong,
|
|
35
|
-
(ds, rest) =>
|
|
36
|
-
rest.slice(0, 2) === '**' && isEndTightNodes(ds)
|
|
37
|
-
? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
|
|
38
|
-
: [unshift(['**', html('em', defrag(bs))], ds), rest])
|
|
39
|
-
(rest, context) ?? [['**', html('em', defrag(bs))], rest];
|
|
33
|
+
case '***':
|
|
34
|
+
return [[html('em', [html('strong', defrag(bs))])], rest];
|
|
40
35
|
case '**':
|
|
41
36
|
return bind<EmphasisParser>(
|
|
42
37
|
subemphasis,
|
|
@@ -45,8 +40,14 @@ export const emstrong: EmStrongParser = lazy(() => creator(surround(
|
|
|
45
40
|
? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds)))], rest.slice(1)]
|
|
46
41
|
: [unshift(['*', html('strong', defrag(bs))], ds), rest])
|
|
47
42
|
(rest, context) ?? [['*', html('strong', defrag(bs))], rest];
|
|
48
|
-
case '
|
|
49
|
-
return
|
|
43
|
+
case '*':
|
|
44
|
+
return bind<StrongParser>(
|
|
45
|
+
substrong,
|
|
46
|
+
(ds, rest) =>
|
|
47
|
+
rest.slice(0, 2) === '**' && isEndTightNodes(ds)
|
|
48
|
+
? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
|
|
49
|
+
: [unshift(['**', html('em', defrag(bs))], ds), rest])
|
|
50
|
+
(rest, context) ?? [['**', html('em', defrag(bs))], rest];
|
|
50
51
|
}
|
|
51
52
|
assert(false);
|
|
52
53
|
},
|