securemark 0.244.2 → 0.247.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/.eslintrc.json +26 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.js +9304 -0
- package/global.test.d.ts +6 -2
- package/index.ts +4 -0
- package/karma.conf.js +20 -39
- package/markdown.d.ts +31 -19
- package/package.json +29 -34
- package/src/parser/block/extension/table.test.ts +25 -30
- package/src/parser/block/extension/table.ts +38 -38
- package/src/parser/block/reply/quote.test.ts +1 -1
- package/src/parser/inline/math.test.ts +51 -20
- package/src/parser/inline/math.ts +24 -15
- package/src/parser/inline.test.ts +2 -1
- package/src/parser/inline.ts +3 -3
- package/src/renderer/render/code.ts +1 -1
- package/src/renderer/render/media/twitter.ts +2 -2
- package/tsconfig.json +10 -7
- package/webpack.config.js +129 -0
- package/dist/securemark.js +0 -8578
- package/gulpfile.js +0 -208
- package/package-lock.json +0 -11857
package/global.test.d.ts
CHANGED
package/index.ts
ADDED
package/karma.conf.js
CHANGED
|
@@ -1,48 +1,29 @@
|
|
|
1
1
|
module.exports = function (config) {
|
|
2
2
|
config.set({
|
|
3
|
-
|
|
4
|
-
frameworks: ['mocha'],
|
|
3
|
+
browsers: ['Chrome', 'Firefox'],
|
|
4
|
+
frameworks: ['mocha', 'power-assert'],
|
|
5
5
|
files: [
|
|
6
|
-
{ pattern: 'https://
|
|
7
|
-
{ pattern: 'https://
|
|
8
|
-
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/
|
|
9
|
-
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.
|
|
10
|
-
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/
|
|
11
|
-
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/
|
|
12
|
-
{ pattern: '
|
|
13
|
-
{ pattern: 'dist
|
|
6
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js', watched: false, served: false, included: true, integrity: 'sha512-2iwCHjuj+PmdCyvb88rMOch0UcKQxVHi/gsAml1fN3eg82IDaO/cdzzeXX4iF2VzIIes7pODE1/G0ts3QBwslA==' },
|
|
7
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.js', watched: false, served: false, included: true, integrity: 'sha512-XnVGk21Ij51MbU8XezQpkwZ1/GA8b5qmoVGIOdJLBYycutjkaeemipzRJP7P6mEJl99OfnweA7M3e4WLfuG7Aw==' },
|
|
8
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js', watched: false, served: false, included: true, integrity: 'sha512-n/4gHW3atM3QqRcbCn6ewmpxcLAHGaDjpEBu4xZd47N0W2oQ+6q7oc3PXstrJYXcbNU1OHdQ1T7pAP+gi5Yu8g==' },
|
|
9
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/prism.min.js', watched: false, served: false, included: true, integrity: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/prism.js' },
|
|
10
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/autoloader/prism-autoloader.min.js', watched: false, served: false, included: true, integrity: 'sha512-fTl/qcO1VgvKtOMApX2PdZzkziyr2stM65GYPLGuYMnuMm1z2JLJG6XVU7C/mR+E7xBUqCivykuhlzfqxXBXbg==' },
|
|
11
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-chtml.min.js', watched: false, served: false, included: true, integrity: 'sha512-93xLZnNMlYI6xaQPf/cSdXoBZ23DThX7VehiGJJXB76HTTalQKPC5CIHuFX8dlQ5yzt6baBQRJ4sDXhzpojRJA==' },
|
|
12
|
+
{ pattern: 'https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.8/purify.js', watched: false, served: false, included: true, integrity: 'sha512-QaF+0tDlqVmwZaQSc0kImgYmw+Cd66TxA5D9X70I5V9BNSqk6yBTbyqw2VEUsVYV5OTbxw8HD9d45on1wvYv7g==' },
|
|
13
|
+
{ pattern: 'dist/**/*.{js,map}', watched: true, served: true, included: true },
|
|
14
14
|
],
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
options: {
|
|
19
|
-
emitActualCode: false,
|
|
20
|
-
ignoreUpstreamSourceMap: true
|
|
21
|
-
}
|
|
15
|
+
reporters: ['dots', 'coverage'],
|
|
16
|
+
preprocessors: {
|
|
17
|
+
'dist/**/*.js': ['coverage'],
|
|
22
18
|
},
|
|
23
|
-
|
|
24
|
-
coverageIstanbulReporter: {
|
|
25
|
-
reports: ['html', 'lcovonly', 'text-summary'],
|
|
19
|
+
coverageReporter: {
|
|
26
20
|
dir: 'coverage',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
html: {
|
|
32
|
-
subdir: 'html',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
instrumentation: {
|
|
36
|
-
'default-excludes': false,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
coverageIstanbulInstrumenter: {
|
|
40
|
-
esModules: true,
|
|
21
|
+
reporters: [
|
|
22
|
+
{ type: 'html', subdir: browser => browser.split(/\s/)[0] },
|
|
23
|
+
{ type: 'text-summary', subdir: '.', file: 'summary.txt' },
|
|
24
|
+
],
|
|
41
25
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
browserDisconnectTimeout: 30000,
|
|
45
|
-
browsers: ['Chrome'],
|
|
46
|
-
singleRun: true,
|
|
26
|
+
browserDisconnectTimeout: 60 * 1e3,
|
|
27
|
+
browserNoActivityTimeout: 90 * 1e3,
|
|
47
28
|
});
|
|
48
29
|
};
|
package/markdown.d.ts
CHANGED
|
@@ -652,6 +652,7 @@ export namespace MarkdownParser {
|
|
|
652
652
|
InlineParser.ReferenceParser,
|
|
653
653
|
InlineParser.TemplateParser,
|
|
654
654
|
InlineParser.CommentParser,
|
|
655
|
+
InlineParser.MathParser,
|
|
655
656
|
InlineParser.ExtensionParser,
|
|
656
657
|
InlineParser.RubyParser,
|
|
657
658
|
InlineParser.LinkParser,
|
|
@@ -664,7 +665,6 @@ export namespace MarkdownParser {
|
|
|
664
665
|
InlineParser.StrongParser,
|
|
665
666
|
InlineParser.EmphasisParser,
|
|
666
667
|
InlineParser.CodeParser,
|
|
667
|
-
InlineParser.MathParser,
|
|
668
668
|
InlineParser.HTMLEntityParser,
|
|
669
669
|
InlineParser.ShortmediaParser,
|
|
670
670
|
InlineParser.AutolinkParser,
|
|
@@ -748,6 +748,36 @@ export namespace MarkdownParser {
|
|
|
748
748
|
InlineParser,
|
|
749
749
|
]> {
|
|
750
750
|
}
|
|
751
|
+
export interface MathParser extends
|
|
752
|
+
// $expr$
|
|
753
|
+
// ${expr}$
|
|
754
|
+
Inline<'math'>,
|
|
755
|
+
Parser<HTMLElement, Context, [
|
|
756
|
+
MathParser.BracketParser,
|
|
757
|
+
Parser<string, Context, [
|
|
758
|
+
MathParser.BracketParser,
|
|
759
|
+
MathParser.QuoteParser,
|
|
760
|
+
SourceParser.StrParser,
|
|
761
|
+
]>,
|
|
762
|
+
]> {
|
|
763
|
+
}
|
|
764
|
+
export namespace MathParser {
|
|
765
|
+
export interface BracketParser extends
|
|
766
|
+
Inline<'math/bracket'>,
|
|
767
|
+
Parser<HTMLElement, Context, [
|
|
768
|
+
BracketParser,
|
|
769
|
+
SourceParser.EscapableSourceParser,
|
|
770
|
+
]> {
|
|
771
|
+
}
|
|
772
|
+
export interface QuoteParser extends
|
|
773
|
+
Inline<'math/quote'>,
|
|
774
|
+
Parser<HTMLElement, Context, [
|
|
775
|
+
QuoteParser,
|
|
776
|
+
BracketParser,
|
|
777
|
+
SourceParser.StrParser,
|
|
778
|
+
]> {
|
|
779
|
+
}
|
|
780
|
+
}
|
|
751
781
|
export interface ExtensionParser extends
|
|
752
782
|
// [#abc]
|
|
753
783
|
Inline<'extension'>,
|
|
@@ -1039,24 +1069,6 @@ export namespace MarkdownParser {
|
|
|
1039
1069
|
SourceParser.StrParser,
|
|
1040
1070
|
]> {
|
|
1041
1071
|
}
|
|
1042
|
-
export interface MathParser extends
|
|
1043
|
-
// $expr$
|
|
1044
|
-
// ${expr}$
|
|
1045
|
-
Inline<'math'>,
|
|
1046
|
-
Parser<HTMLElement, Context, [
|
|
1047
|
-
SourceParser.StrParser,
|
|
1048
|
-
MathParser.BracketParser,
|
|
1049
|
-
]> {
|
|
1050
|
-
}
|
|
1051
|
-
export namespace MathParser {
|
|
1052
|
-
export interface BracketParser extends
|
|
1053
|
-
Inline<'math/bracket'>,
|
|
1054
|
-
Parser<HTMLElement, Context, [
|
|
1055
|
-
BracketParser,
|
|
1056
|
-
SourceParser.EscapableSourceParser,
|
|
1057
|
-
]> {
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
1072
|
export interface HTMLEntityParser extends
|
|
1061
1073
|
// ©
|
|
1062
1074
|
Inline<'htmlentity'>,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.247.0",
|
|
4
4
|
"description": "Secure markdown renderer working on browsers for user input data.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/falsandtru/securemark",
|
|
@@ -13,22 +13,20 @@
|
|
|
13
13
|
"latex"
|
|
14
14
|
],
|
|
15
15
|
"types": "./index.d.ts",
|
|
16
|
-
"main": "./dist/
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"
|
|
19
|
+
"index.*",
|
|
20
20
|
"src",
|
|
21
21
|
"test",
|
|
22
|
+
"*.ts",
|
|
22
23
|
"*.js",
|
|
23
24
|
"*.json",
|
|
25
|
+
"*.map",
|
|
24
26
|
"*.md",
|
|
25
27
|
"NOTICE",
|
|
26
28
|
"LICENSE"
|
|
27
29
|
],
|
|
28
|
-
"browserify-shim": {
|
|
29
|
-
"prismjs": "global:Prism",
|
|
30
|
-
"dompurify": "global:DOMPurify"
|
|
31
|
-
},
|
|
32
30
|
"devDependencies": {
|
|
33
31
|
"@types/dompurify": "2.3.3",
|
|
34
32
|
"@types/jquery": "3.5.14",
|
|
@@ -36,41 +34,38 @@
|
|
|
36
34
|
"@types/mocha": "9.1.1",
|
|
37
35
|
"@types/power-assert": "1.5.8",
|
|
38
36
|
"@types/prismjs": "1.26.0",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"eslint
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"gulp-header": "^2.0.9",
|
|
49
|
-
"gulp-load-plugins": "^2.0.7",
|
|
50
|
-
"gulp-mocha": "^8.0.0",
|
|
51
|
-
"gulp-rename": "^2.0.0",
|
|
52
|
-
"gulp-unassert": "^2.0.0",
|
|
53
|
-
"karma": "^6.3.19",
|
|
37
|
+
"@typescript-eslint/parser": "^5.25.0",
|
|
38
|
+
"babel-loader": "^8.2.5",
|
|
39
|
+
"babel-plugin-unassert": "^3.2.0",
|
|
40
|
+
"concurrently": "^7.2.0",
|
|
41
|
+
"eslint": "^8.15.0",
|
|
42
|
+
"eslint-plugin-redos": "^4.4.0",
|
|
43
|
+
"eslint-webpack-plugin": "^3.1.1",
|
|
44
|
+
"glob": "^8.0.3",
|
|
45
|
+
"karma": "^6.3.20",
|
|
54
46
|
"karma-chrome-launcher": "^3.1.1",
|
|
55
|
-
"karma-coverage
|
|
56
|
-
"karma-coverage-istanbul-reporter": "^3.0.3",
|
|
57
|
-
"karma-espower-preprocessor": "^1.2.0",
|
|
47
|
+
"karma-coverage": "^2.2.0",
|
|
58
48
|
"karma-firefox-launcher": "^2.1.2",
|
|
59
49
|
"karma-mocha": "^2.0.1",
|
|
50
|
+
"karma-power-assert": "^1.0.0",
|
|
60
51
|
"mocha": "^10.0.0",
|
|
61
|
-
"npm-check-updates": "^
|
|
62
|
-
"power-assert": "^1.6.1",
|
|
52
|
+
"npm-check-updates": "^13.0.1",
|
|
63
53
|
"semver": "^7.3.7",
|
|
64
|
-
"spica": "0.0.
|
|
65
|
-
"
|
|
66
|
-
"typed-dom": "0.0.
|
|
67
|
-
"typed-query-selector": "^2.6.1",
|
|
54
|
+
"spica": "0.0.551",
|
|
55
|
+
"ts-loader": "^9.3.0",
|
|
56
|
+
"typed-dom": "^0.0.295",
|
|
68
57
|
"typescript": "4.6.4",
|
|
69
|
-
"
|
|
70
|
-
"
|
|
58
|
+
"webpack": "^5.72.1",
|
|
59
|
+
"webpack-cli": "^4.9.2",
|
|
60
|
+
"webpack-merge": "^5.8.0"
|
|
71
61
|
},
|
|
72
62
|
"scripts": {
|
|
73
|
-
"
|
|
63
|
+
"update": "ncu -u && npm i --no-shrinkwrap && bundle update",
|
|
64
|
+
"dev": "concurrently \"webpack --env mode=test -w\" \"karma start --auto-watch --reporters dots\" \"webpack --env mode=dist -w --output-path ./gh-pages/assets/dist\" \"bundle exec jekyll serve -s ./gh-pages -d ./gh-pages/_site --incremental\"",
|
|
65
|
+
"test": "webpack --env mode=test && karma start --single-run --concurrency 1",
|
|
66
|
+
"lint": "webpack --env mode=lint",
|
|
67
|
+
"bench": "webpack --env mode=bench && karma start --single-run --concurrency 1 --reporters dots",
|
|
68
|
+
"dist": "webpack --env mode=dist"
|
|
74
69
|
},
|
|
75
70
|
"author": "falsandtru",
|
|
76
71
|
"license": "UNLICENSED"
|
|
@@ -10,20 +10,6 @@ describe('Unit: parser/block/extension/table', () => {
|
|
|
10
10
|
it('invalid', () => {
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('~~~table a\n-\n~~~')), [['<pre class="invalid" translate="no">~~~table a\n-\n~~~</pre>'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser(`~~~table\n0${'\n'.repeat(10001)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
13
|
-
assert.deepStrictEqual(
|
|
14
|
-
inspect(parser([
|
|
15
|
-
'~~~table',
|
|
16
|
-
`${[...Array(33)].map((_, i) => `${i + 1}`).join('\n')}`,
|
|
17
|
-
'~~~'
|
|
18
|
-
].join('\n'))),
|
|
19
|
-
[[`<pre class="invalid" translate="no">~~~table\n${[...Array(33)].map((_, i) => `${i + 1}`).join('\n')}\n~~~</pre>`], '']);
|
|
20
|
-
assert.deepStrictEqual(
|
|
21
|
-
inspect(parser([
|
|
22
|
-
'~~~table',
|
|
23
|
-
'::33 1',
|
|
24
|
-
'~~~'
|
|
25
|
-
].join('\n'))),
|
|
26
|
-
[[`<pre class="invalid" translate="no">~~~table\n::33 1\n~~~</pre>`], '']);
|
|
27
13
|
});
|
|
28
14
|
|
|
29
15
|
it('data', () => {
|
|
@@ -483,8 +469,8 @@ describe('Unit: parser/block/extension/table', () => {
|
|
|
483
469
|
assert.deepStrictEqual(
|
|
484
470
|
inspect(parser([
|
|
485
471
|
'~~~table',
|
|
486
|
-
`-\n# 1\n${[...Array(
|
|
487
|
-
`-\n#! 1\n${[...Array(
|
|
472
|
+
`-\n# 1\n${[...Array(32)].map((_, i) => `: ${i + 2}`).join('\n')}`,
|
|
473
|
+
`-\n#! 1\n${[...Array(32)].map((_, i) => `: ${i + 2}`).join('\n')}`,
|
|
488
474
|
'~~~'
|
|
489
475
|
].join('\n'))),
|
|
490
476
|
[[html('table', [
|
|
@@ -492,52 +478,52 @@ describe('Unit: parser/block/extension/table', () => {
|
|
|
492
478
|
html('tbody', [
|
|
493
479
|
html('tr', [
|
|
494
480
|
html('th', '1'),
|
|
495
|
-
...[...Array(
|
|
481
|
+
...[...Array(32)].map((_, i) => html('td', `${i + 2}`)),
|
|
496
482
|
]),
|
|
497
483
|
html('tr', [
|
|
498
484
|
html('th', { class: 'highlight' }, '1'),
|
|
499
|
-
...[...Array(
|
|
485
|
+
...[...Array(32)].map((_, i) => html('td', { class: 'highlight', highlight: 'h' }, `${i + 2}`)),
|
|
500
486
|
]),
|
|
501
487
|
]),
|
|
502
488
|
html('tfoot')]).outerHTML], '']);
|
|
503
489
|
assert.deepStrictEqual(
|
|
504
490
|
inspect(parser([
|
|
505
491
|
'~~~table',
|
|
506
|
-
`-\n${[...Array(
|
|
507
|
-
`-\n${[...Array(
|
|
492
|
+
`-\n${[...Array(32)].map((_, i) => `: ${i + 1}`).join('\n')}\n# 33`,
|
|
493
|
+
`-\n${[...Array(32)].map((_, i) => `: ${i + 1}`).join('\n')}\n#! 33`,
|
|
508
494
|
'~~~'
|
|
509
495
|
].join('\n'))),
|
|
510
496
|
[[html('table', [
|
|
511
497
|
html('thead'),
|
|
512
498
|
html('tbody', [
|
|
513
499
|
html('tr', [
|
|
514
|
-
...[...Array(
|
|
515
|
-
html('th', '
|
|
500
|
+
...[...Array(32)].map((_, i) => html('td', `${i + 1}`)),
|
|
501
|
+
html('th', '33'),
|
|
516
502
|
]),
|
|
517
503
|
html('tr', [
|
|
518
|
-
...[...Array(
|
|
519
|
-
html('th', { class: 'highlight' }, '
|
|
504
|
+
...[...Array(32)].map((_, i) => html('td', { class: 'highlight', highlight: 'h' }, `${i + 1}`)),
|
|
505
|
+
html('th', { class: 'highlight' }, '33'),
|
|
520
506
|
]),
|
|
521
507
|
]),
|
|
522
508
|
html('tfoot')]).outerHTML], '']);
|
|
523
509
|
assert.deepStrictEqual(
|
|
524
510
|
inspect(parser([
|
|
525
511
|
'~~~table',
|
|
526
|
-
`-\n${[...Array(
|
|
527
|
-
`-\n${[...Array(
|
|
512
|
+
`-\n${[...Array(32)].map((_, i) => `# ${i + 1}`).join('\n')}\n#! 33`,
|
|
513
|
+
`-\n${[...Array(33)].map((_, i) => `: ${i + 1}`).join('\n')}`,
|
|
528
514
|
'~~~'
|
|
529
515
|
].join('\n'))),
|
|
530
516
|
[[html('table', [
|
|
531
517
|
html('thead', [
|
|
532
518
|
html('tr', [
|
|
533
|
-
...[...Array(
|
|
534
|
-
html('th', { class: 'highlight' }, '
|
|
519
|
+
...[...Array(32)].map((_, i) => html('th', `${i + 1}`)),
|
|
520
|
+
html('th', { class: 'highlight' }, '33'),
|
|
535
521
|
]),
|
|
536
522
|
]),
|
|
537
523
|
html('tbody', [
|
|
538
524
|
html('tr', [
|
|
539
|
-
...[...Array(
|
|
540
|
-
html('td', { class: 'highlight', highlight: 'v' }, '
|
|
525
|
+
...[...Array(32)].map((_, i) => html('td', `${i + 1}`)),
|
|
526
|
+
html('td', { class: 'highlight', highlight: 'v' }, '33'),
|
|
541
527
|
]),
|
|
542
528
|
]),
|
|
543
529
|
html('tfoot')]).outerHTML], '']);
|
|
@@ -668,6 +654,15 @@ describe('Unit: parser/block/extension/table', () => {
|
|
|
668
654
|
]).outerHTML], '']);
|
|
669
655
|
});
|
|
670
656
|
|
|
657
|
+
it('type', () => {
|
|
658
|
+
assert.deepStrictEqual(
|
|
659
|
+
inspect(parser('~~~table/invalid\n~~~')),
|
|
660
|
+
[['<pre class="invalid" translate="no">~~~table/invalid\n~~~</pre>'], '']);
|
|
661
|
+
assert.deepStrictEqual(
|
|
662
|
+
inspect(parser('~~~table/grid\n~~~')),
|
|
663
|
+
[[html('table', { 'data-type': 'grid' }).outerHTML], '']);
|
|
664
|
+
});
|
|
665
|
+
|
|
671
666
|
});
|
|
672
667
|
|
|
673
668
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { undefined, Array } from 'spica/global';
|
|
1
|
+
import { undefined, BigInt, Array } from 'spica/global';
|
|
2
2
|
import { max, min, isArray } from 'spica/alias';
|
|
3
3
|
import { ExtensionParser } from '../../block';
|
|
4
4
|
import { Tree, eval } from '../../../combinator/data/parser';
|
|
5
|
-
import { union, subsequence, inits, some, block, line, validate, fence, rewrite, creator, open, clear, convert, trim, dup,
|
|
5
|
+
import { union, subsequence, inits, some, block, line, validate, fence, rewrite, creator, open, clear, convert, trim, dup, lazy, fmap } from '../../../combinator';
|
|
6
6
|
import { inline } from '../../inline';
|
|
7
7
|
import { str, anyline, emptyline, contentline } from '../../source';
|
|
8
8
|
import { localize } from '../../locale';
|
|
9
9
|
import { visualize } from '../../util';
|
|
10
|
-
import { html, defrag } from 'typed-dom/dom';
|
|
10
|
+
import { html, define, defrag } from 'typed-dom/dom';
|
|
11
11
|
import { unshift, splice } from 'spica/array';
|
|
12
12
|
|
|
13
13
|
import TableParser = ExtensionParser.TableParser;
|
|
@@ -15,7 +15,7 @@ import RowParser = TableParser.RowParser;
|
|
|
15
15
|
import AlignParser = TableParser.AlignParser;
|
|
16
16
|
import CellParser = TableParser.CellParser;
|
|
17
17
|
|
|
18
|
-
const opener = /^(~{3,})table(?!\S)([^\n]*)(?:$|\n)/;
|
|
18
|
+
const opener = /^(~{3,})table(?:\/(\S+))?(?!\S)([^\n]*)(?:$|\n)/;
|
|
19
19
|
|
|
20
20
|
export const segment: TableParser.SegmentParser = block(validate('~~~',
|
|
21
21
|
clear(fence(opener, 10000))));
|
|
@@ -23,10 +23,10 @@ export const segment: TableParser.SegmentParser = block(validate('~~~',
|
|
|
23
23
|
export const segment_: TableParser.SegmentParser = block(validate('~~~',
|
|
24
24
|
clear(fence(opener, 10000, false))), false);
|
|
25
25
|
|
|
26
|
-
export const table: TableParser = block(validate('~~~',
|
|
26
|
+
export const table: TableParser = block(validate('~~~', fmap(
|
|
27
27
|
fence(opener, 10000),
|
|
28
28
|
// Bug: Type mismatch between outer and inner.
|
|
29
|
-
([body, overflow, closer, opener, delim, param]: string[], _, context) => {
|
|
29
|
+
([body, overflow, closer, opener, delim, type, param]: string[], _, context) => {
|
|
30
30
|
if (!closer || overflow || param.trimStart()) return [html('pre', {
|
|
31
31
|
class: 'invalid',
|
|
32
32
|
translate: 'no',
|
|
@@ -37,20 +37,21 @@ export const table: TableParser = block(validate('~~~', recover(fmap(
|
|
|
37
37
|
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
38
38
|
'Invalid argument',
|
|
39
39
|
}, `${opener}${body}${overflow || closer}`)];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
switch (type) {
|
|
41
|
+
case 'grid':
|
|
42
|
+
case undefined:
|
|
43
|
+
return (eval(parser(body, context)) ?? [html('table')])
|
|
44
|
+
.map(el => define(el, { 'data-type': type }));
|
|
45
|
+
default:
|
|
46
|
+
return [html('pre', {
|
|
47
|
+
class: 'invalid',
|
|
48
|
+
translate: 'no',
|
|
49
|
+
'data-invalid-syntax': 'table',
|
|
50
|
+
'data-invalid-type': 'argument',
|
|
51
|
+
'data-invalid-message': 'Invalid table type',
|
|
52
|
+
}, `${opener}${body}${closer}`)];
|
|
53
|
+
}
|
|
54
|
+
})));
|
|
54
55
|
|
|
55
56
|
const parser: TableParser = lazy(() => block(localize(fmap(
|
|
56
57
|
some(union([row])),
|
|
@@ -144,7 +145,7 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
|
|
|
144
145
|
const valigns: ('middle' | 'top' | 'bottom' | '')[] = [];
|
|
145
146
|
let target = thead;
|
|
146
147
|
let ranges: Record<number, Record<number, HTMLTableCellElement>> = {};
|
|
147
|
-
let verticalHighlights =
|
|
148
|
+
let verticalHighlights = 0n;
|
|
148
149
|
ROW:
|
|
149
150
|
for (let i = 0; i < rows.length; ++i) {
|
|
150
151
|
// Copy to make them retryable.
|
|
@@ -214,25 +215,25 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
|
|
|
214
215
|
}
|
|
215
216
|
assert(valigns.length > 0);
|
|
216
217
|
const row = html('tr');
|
|
217
|
-
let heads =
|
|
218
|
-
let highlights =
|
|
218
|
+
let heads = 0n;
|
|
219
|
+
let highlights = 0n;
|
|
219
220
|
let hasDataCell = false;
|
|
220
|
-
let lHeadCellIdx:
|
|
221
|
-
let rHeadCellIdx:
|
|
222
|
-
for (let j = 0; j < cells.length
|
|
221
|
+
let lHeadCellIdx: bigint;
|
|
222
|
+
let rHeadCellIdx: bigint;
|
|
223
|
+
for (let j = 0, jn = 0n; j < cells.length; jn = BigInt(++j)) {
|
|
223
224
|
const isVirtual = !!ranges[i]?.[j];
|
|
224
225
|
const cell = isVirtual
|
|
225
226
|
? splice(cells, j, 0, undefined) && ranges[i][j]
|
|
226
227
|
: cells[j];
|
|
227
228
|
const isHeadCell = cell.tagName === 'TH';
|
|
228
|
-
heads |=
|
|
229
|
-
highlights |=
|
|
229
|
+
heads |= BigInt(isHeadCell) << jn;
|
|
230
|
+
highlights |= BigInt(cell.classList.contains('highlight')) << jn;
|
|
230
231
|
hasDataCell ||= !isHeadCell;
|
|
231
232
|
if (isHeadCell && !hasDataCell) {
|
|
232
|
-
lHeadCellIdx =
|
|
233
|
+
lHeadCellIdx = jn;
|
|
233
234
|
}
|
|
234
235
|
if (isHeadCell && hasDataCell) {
|
|
235
|
-
rHeadCellIdx ??=
|
|
236
|
+
rHeadCellIdx ??= jn;
|
|
236
237
|
}
|
|
237
238
|
const rowSpan = cell.rowSpan;
|
|
238
239
|
assert(rowSpan > 0);
|
|
@@ -247,8 +248,8 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
|
|
|
247
248
|
assert(colSpan > 0);
|
|
248
249
|
if (colSpan > 1) {
|
|
249
250
|
splice(cells, j + 1, 0, ...Array(colSpan - 1));
|
|
250
|
-
heads |= +`0b${`${heads &
|
|
251
|
-
highlights |= +`0b${`${highlights &
|
|
251
|
+
heads |= BigInt(+`0b${`${heads & 1n << jn && 1}`.repeat(colSpan)}`) << jn;
|
|
252
|
+
highlights |= BigInt(+`0b${`${highlights & 1n << jn && 1}`.repeat(colSpan)}`) << jn;
|
|
252
253
|
j += colSpan - 1;
|
|
253
254
|
}
|
|
254
255
|
if (target === thead) {
|
|
@@ -282,20 +283,19 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
|
|
|
282
283
|
aligns[j] && cell.setAttribute('align', aligns[j]);
|
|
283
284
|
valigns[j] && cell.setAttribute('valign', valigns[j]);
|
|
284
285
|
}
|
|
285
|
-
if (cells.length > 32) throw new Error('Number of columns must be 32 or less');
|
|
286
286
|
target.appendChild(row);
|
|
287
287
|
switch (target) {
|
|
288
288
|
case thead:
|
|
289
289
|
verticalHighlights = heads & highlights;
|
|
290
290
|
continue;
|
|
291
291
|
case tbody:
|
|
292
|
-
lHeadCellIdx ??= -
|
|
293
|
-
rHeadCellIdx ??= -
|
|
292
|
+
lHeadCellIdx ??= -1n;
|
|
293
|
+
rHeadCellIdx ??= -1n;
|
|
294
294
|
const tHighlights = verticalHighlights;
|
|
295
295
|
const horizontalHighlights = heads & highlights;
|
|
296
|
-
const lHighlight = ~lHeadCellIdx && horizontalHighlights &
|
|
297
|
-
const rHighlight = ~rHeadCellIdx && horizontalHighlights &
|
|
298
|
-
for (let i = 0, m =
|
|
296
|
+
const lHighlight = ~lHeadCellIdx && horizontalHighlights & 1n << lHeadCellIdx;
|
|
297
|
+
const rHighlight = ~rHeadCellIdx && horizontalHighlights & 1n << rHeadCellIdx;
|
|
298
|
+
for (let i = 0, m = 1n; i < cells.length; ++i, m <<= 1n) {
|
|
299
299
|
const cell = cells[i];
|
|
300
300
|
if (!cell) continue;
|
|
301
301
|
if (heads & m) continue;
|
|
@@ -52,7 +52,7 @@ describe('Unit: parser/block/reply/quote', () => {
|
|
|
52
52
|
assert.deepStrictEqual(inspect(parser('> > a\n> > b\n> > c')), [['<span class="quote">> > a<br>> > b<br>> > c</span>', '<br>'], '']);
|
|
53
53
|
assert.deepStrictEqual(inspect(parser('> > > a\n> > > b')), [['<span class="quote">> > > a<br>> > > b</span>', '<br>'], '']);
|
|
54
54
|
assert.deepStrictEqual(inspect(parser('> #a')), [['<span class="quote">> <a href="/hashtags/a" class="hashtag">#a</a></span>', '<br>'], '']);
|
|
55
|
-
assert.deepStrictEqual(inspect(parser('>
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('> $-a, $-b')), [['<span class="quote">> $-a, $-b</span>', '<br>'], '']);
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('> $a=b$')), [['<span class="quote">> <span class="math" translate="no" data-src="$a=b$">$a=b$</span></span>', '<br>'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('> ${a}$')), [['<span class="quote">> <span class="math" translate="no" data-src="${a}$">${a}$</span></span>', '<br>'], '']);
|
|
58
58
|
});
|