securemark 0.247.0 → 0.248.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.248.0
4
+
5
+ - Change html parser not to limit nesting patterns of HTML tags.
6
+
7
+ ## 0.247.2
8
+
9
+ - Fix math parser.
10
+
11
+ ## 0.247.1
12
+
13
+ - Fix math parser.
14
+
3
15
  ## 0.247.0
4
16
 
5
17
  - Refine math parser.
package/design.md CHANGED
@@ -278,8 +278,11 @@ CodeMirrorが素では速いがVimModeでは数万文字程度でも耐え難く
278
278
 
279
279
  ### バックトラック
280
280
 
281
- SecuremarkのAnnotation構文に典型的であるように文脈を変える構文が存在する場合文脈の相違から解析結果を再利用不能な(`αA'β | αAB`)バックトラックが再帰的に生じ、このような言語を線形時間で解析することは基本的に不可能であると思われる。
282
- このため線形時間で解析可能な文法に制約されるCommonMarkがこの制約を破らずこのような文脈不確定文法を導入することは(リンク構文のような特殊な解決方法を取れる場合を除き)基本的に不可能であるという拡張性の限界が存在する。
281
+ SecuremarkのAnnotation構文に典型的であるように文脈を変更する構文とその文脈に依存し変更される他の構文が存在する場合文脈の相違から解析結果を再利用不能な(`αA'β | αAB`)バックトラックが生じる。ここで解析中に文脈依存構文に遭遇した時、現在の文脈での解析を継続する場合はバックトラックが再帰的に生じ線形時間で解析できず、現在の文脈での解析を中止し直前の文脈を継続または新たな文脈を開始する場合は線形時間で解析できる。
282
+ CommonMarkはLink構文から明らかなように後者の解析方法により線形時間で解析できる言語であるがこれは同時に文脈依存構文の正当な入れ子表現すら解析できず文脈依存構文の存在する数に応じて指数関数的に構文の壊れやすさの増す脆く拡張性の低い言語であることを意味する。
283
+ 従って線形時間で解析可能な文法に制約されるCommonMarkには文脈依存構文を入れ子表現の広範な制限ならびに構文の可読性および開始記号の信頼性の指数関数的な低下と引き換えにしか追加できないという拡張性の限界が存在する。
284
+ 対してSecuremarkは線形時間で解析不能な前者の解析方法を採用し解析時間と解析範囲の局限により線形時間で解析不能な入力の影響を局限することでこの制限を回避している。
285
+ ただし実際には文脈依存構文の入れ子表現はほとんどがリンクの入れ子不可制約として正当に制限されており開始記号の文字列(終端記号)としての正当な使用も稀と思われるため実用上差異が生じることはほとんどないと思われる。
283
286
 
284
287
  ### 標準化
285
288
 
@@ -296,5 +299,5 @@ MarkdownはGFMのように最初から高機能で完成度の高い拡張不要
296
299
 
297
300
  ### Data URI
298
301
 
299
- Data URIは保存および転送容量削減ならびに集約的管理のためサポートしない。
300
- 特に規制および公開レベルの媒体別の設定のためテキストとメディアの分離が必須となる。
302
+ Data URIは保存および転送容量削減ならびにユーザーおよび管理者双方の集約的管理のためサポートしない。
303
+ 特に規制および公開レベルの媒体別設定の実現のためテキストとメディアの分離が必須となる。
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.247.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.248.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
2
2
  (function webpackUniversalModuleDefinition(root, factory) {
3
3
  if(typeof exports === 'object' && typeof module === 'object')
4
4
  module.exports = factory(require("DOMPurify"), require("Prism"));
@@ -5367,7 +5367,6 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0,
5367
5367
 
5368
5368
  }
5369
5369
  },
5370
- state: global_1.undefined,
5371
5370
  delimiters: global_1.undefined
5372
5371
  }, (0, util_1.trimSpaceStart)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, ')', /^\\?\n/)]))))), '))'), ns => [(0, dom_1.html)('sup', {
5373
5372
  class: 'annotation'
@@ -5754,7 +5753,7 @@ const dom_1 = __webpack_require__(3252);
5754
5753
 
5755
5754
  const array_1 = __webpack_require__(8112);
5756
5755
 
5757
- exports.deletion = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)((0, source_1.str)('~~'), (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n?/, '~~')), (0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, '~'), true)])), (0, source_1.str)('~~'), false, ([, bs], rest) => [[(0, dom_1.html)('del', (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest])));
5756
+ exports.deletion = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)((0, source_1.str)('~~'), (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n/, '~~')), (0, combinator_1.open)(/^\n/, (0, combinator_1.some)(inline_1.inline, '~'), true)])), (0, source_1.str)('~~'), false, ([, bs], rest) => [[(0, dom_1.html)('del', (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest])));
5758
5757
 
5759
5758
  /***/ }),
5760
5759
 
@@ -6184,77 +6183,13 @@ const attrspec = {
6184
6183
  };
6185
6184
  Object.setPrototypeOf(attrspec, null);
6186
6185
  Object.values(attrspec).forEach(o => Object.setPrototypeOf(o, null));
6187
- exports.html = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('<', (0, combinator_1.validate)(/^<[a-z]+(?=[^\S\n]|>)/, (0, combinator_1.union)([(0, combinator_1.match)(/^(?=<(wbr)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)(`<${tag}`, (0, combinator_1.some)((0, combinator_1.union)([exports.attribute])), /^\s*>/, true, ([, bs = []], rest) => [[(0, dom_1.html)(tag, attributes('html', [], attrspec[tag], bs))], rest]), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<(sup|sub|small)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.validate)(`<${tag}`, `</${tag}>`, (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^\s*>/), true), (0, util_1.startLoose)((0, combinator_1.context)((() => {
6188
- switch (tag) {
6189
- case 'sup':
6190
- case 'sub':
6191
- return {
6192
- state: {
6193
- in: {
6194
- supsub: true
6195
- }
6196
- },
6197
- syntax: {
6198
- inline: {
6199
- annotation: false,
6200
- reference: false,
6201
- media: false
6202
- }
6203
- }
6204
- };
6205
-
6206
- case 'small':
6207
- return {
6208
- state: {
6209
- in: {
6210
- small: true
6211
- }
6212
- },
6213
- syntax: {
6214
- inline: {
6215
- media: false
6216
- }
6217
- }
6218
- };
6219
-
6220
- default:
6221
- return {};
6222
- }
6223
- })(), (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n?/, `</${tag}>`)), (0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, '</'), true)]), `</${tag}>`)), `</${tag}>`), (0, source_1.str)(`</${tag}>`), false, ([as, bs, cs], rest, context) => [[elem(tag, as, (0, dom_1.defrag)(bs), cs, context)], rest])), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<(bdo|bdi)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.validate)(`<${tag}`, `</${tag}>`, (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^\s*>/), true), (0, util_1.startLoose)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n?/, `</${tag}>`)), (0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, '</'), true)]), `</${tag}>`), `</${tag}>`), (0, source_1.str)(`</${tag}>`), false, ([as, bs, cs], rest, context) => [[elem(tag, as, (0, dom_1.defrag)(bs), cs, context)], rest], ([as, bs], rest) => as.length === 1 ? [(0, array_1.unshift)(as, bs), rest] : global_1.undefined)), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<([a-z]+)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.validate)(`<${tag}`, `</${tag}>`, (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^\s*>/), true), (0, util_1.startLoose)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n?/, `</${tag}>`)), (0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, '</'), true)]), `</${tag}>`), `</${tag}>`), (0, source_1.str)(`</${tag}>`), false, ([as, bs, cs], rest, context) => [[elem(tag, as, (0, dom_1.defrag)(bs), cs, context)], rest], ([as, bs], rest) => as.length === 1 ? [(0, array_1.unshift)(as, bs), rest] : global_1.undefined)), ([, tag]) => tag, new cache_1.Cache(10000)))])))));
6186
+ exports.html = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('<', (0, combinator_1.validate)(/^<[a-z]+(?=[^\S\n]|>)/, (0, combinator_1.union)([(0, combinator_1.match)(/^(?=<(wbr)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)(`<${tag}`, (0, combinator_1.some)((0, combinator_1.union)([exports.attribute])), /^\s*>/, true, ([, bs = []], rest) => [[(0, dom_1.html)(tag, attributes('html', [], attrspec[tag], bs))], rest]), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<(sup|sub|small|bdo|bdi)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.validate)(`<${tag}`, `</${tag}>`, (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^\s*>/), true), (0, util_1.startLoose)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n/, `</${tag}>`)), (0, combinator_1.open)(/^\n/, (0, combinator_1.some)(inline_1.inline, `</${tag}>`), true)]), `</${tag}>`), `</${tag}>`), (0, source_1.str)(`</${tag}>`), false, ([as, bs, cs], rest) => [[elem(tag, as, (0, dom_1.defrag)(bs), cs)], rest], ([as, bs], rest) => as.length === 1 ? [(0, array_1.unshift)(as, bs), rest] : global_1.undefined)), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<([a-z]+)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.validate)(`<${tag}`, `</${tag}>`, (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^\s*>/), true), (0, util_1.startLoose)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n/, `</${tag}>`)), (0, combinator_1.open)(/^\n/, (0, combinator_1.some)(inline_1.inline, `</${tag}>`), true)]), `</${tag}>`), `</${tag}>`), (0, source_1.str)(`</${tag}>`), false, ([as, bs, cs], rest) => [[elem(tag, as, (0, dom_1.defrag)(bs), cs)], rest], ([as, bs], rest) => as.length === 1 ? [(0, array_1.unshift)(as, bs), rest] : global_1.undefined)), ([, tag]) => tag, new cache_1.Cache(10000)))])))));
6224
6187
  exports.attribute = (0, combinator_1.union)([(0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/)]);
6225
6188
 
6226
- function elem(tag, as, bs, cs, context) {
6189
+ function elem(tag, as, bs, cs) {
6227
6190
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag <${tag}>`, as, bs, cs);
6228
-
6229
- switch (tag) {
6230
- case 'sup':
6231
- case 'sub':
6232
- switch (true) {
6233
- case context.state?.in?.supsub:
6234
- return invalid('nest', `<${tag}> HTML tag cannot be used in <sup> or <sub> HTML tag`, as, bs, cs);
6235
- }
6236
-
6237
- break;
6238
-
6239
- case 'small':
6240
- switch (true) {
6241
- case context.state?.in?.supsub:
6242
- case context.state?.in?.small:
6243
- return invalid('nest', `<${tag}> HTML tag cannot be used in <sup>, <sub>, or <small> HTML tag`, as, bs, cs);
6244
- }
6245
-
6246
- break;
6247
- }
6248
-
6249
6191
  const attrs = attributes('html', [], attrspec[tag], as.slice(1, -1));
6250
-
6251
- switch (true) {
6252
- case 'data-invalid-syntax' in attrs:
6253
- return invalid('attribute', 'Invalid HTML attribute', as, bs, cs);
6254
-
6255
- default:
6256
- return (0, dom_1.html)(tag, attrs, bs);
6257
- }
6192
+ return 'data-invalid-syntax' in attrs ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs) : (0, dom_1.html)(tag, attrs, bs);
6258
6193
  }
6259
6194
 
6260
6195
  function invalid(type, message, as, bs, cs) {
@@ -6356,7 +6291,7 @@ const dom_1 = __webpack_require__(3252);
6356
6291
 
6357
6292
  const array_1 = __webpack_require__(8112);
6358
6293
 
6359
- exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)((0, source_1.str)('++'), (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n?/, '++')), (0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, '+'), true)])), (0, source_1.str)('++'), false, ([, bs], rest) => [[(0, dom_1.html)('ins', (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest])));
6294
+ exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)((0, source_1.str)('++'), (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, util_1.blank)(/\n/, '++')), (0, combinator_1.open)(/^\n/, (0, combinator_1.some)(inline_1.inline, '+'), true)])), (0, source_1.str)('++'), false, ([, bs], rest) => [[(0, dom_1.html)('ins', (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest])));
6360
6295
 
6361
6296
  /***/ }),
6362
6297
 
@@ -6545,8 +6480,8 @@ const source_1 = __webpack_require__(6743);
6545
6480
  const dom_1 = __webpack_require__(3252);
6546
6481
 
6547
6482
  const syntax = /^(?:[ "([](?!\$)|\\{(?!\$)|\\[\\}$]?|^`|`(?!`)|[!#%&')\x2A-\x5A\]^_\x61-\x7A|~])+/;
6548
- const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![0-9a-z])/i;
6549
- exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('$', (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)('$', bracket, '$'), (0, combinator_1.surround)(/^\$(?!\s)/, (0, combinator_1.some)((0, combinator_1.union)([bracket, quote, (0, source_1.str)(syntax)])), /^\$(?![0-9A-Za-z])/)]), (source, {
6483
+ const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
6484
+ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('$', (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)('$', bracket, '$'), (0, combinator_1.surround)(/^\$(?![\s{}])/, (0, combinator_1.some)((0, combinator_1.union)([bracket, quote, (0, source_1.str)(syntax)])), /^\$(?![0-9A-Za-z])/)]), (source, {
6550
6485
  caches: {
6551
6486
  math: cache
6552
6487
  } = {}
@@ -6559,10 +6494,10 @@ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combin
6559
6494
  translate: 'no',
6560
6495
  'data-invalid-syntax': 'math',
6561
6496
  'data-invalid-type': 'content',
6562
- 'data-invalid-message': `"${source.match(forbiddenCommand)[0]}" command is disallowed`
6497
+ 'data-invalid-message': `"${source.match(forbiddenCommand)[0]}" command is forbidden`
6563
6498
  }, source)], '']))));
6564
6499
  const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)('{', (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.escsource, /^(?:[{}$]|\\?\n)/)])), '}', true)));
6565
- const quote = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)('``', (0, combinator_1.some)((0, combinator_1.union)([quote, bracket, (0, combinator_1.focus)(/^(?:\\[\\{}$]|`(?!`)|[^`{}"$\n])*/, (0, source_1.str)(syntax))])), /^"?/, true)));
6500
+ const quote = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.surround)('``', (0, combinator_1.some)((0, combinator_1.union)([quote, bracket, (0, combinator_1.focus)(/^(?:\\[\\{}$]|`(?!`)|[^`{}"$\n\P{ASCII}])*/u, (0, source_1.str)(syntax))])), /^"?/, true)));
6566
6501
 
6567
6502
  /***/ }),
6568
6503
 
@@ -6700,7 +6635,6 @@ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, c
6700
6635
 
6701
6636
  }
6702
6637
  },
6703
- state: global_1.undefined,
6704
6638
  delimiters: global_1.undefined
6705
6639
  }, (0, combinator_1.subsequence)([abbr, (0, combinator_1.focus)(/^\^[^\S\n]*/, source => [['', source], '']), (0, util_1.trimSpaceStart)((0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/))])))), ']]'), ns => [(0, dom_1.html)('sup', attributes(ns), (0, util_1.trimNodeEnd)((0, dom_1.defrag)(ns)))]))));
6706
6640
  const abbr = (0, combinator_1.creator)((0, combinator_1.fmap)((0, combinator_1.verify)((0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]), /^\|?(?=]])|^\|[^\S\n]*/), (_, rest, context) => (0, util_1.isStartLoose)(rest, context)), ([source]) => [(0, dom_1.html)('abbr', source)]));
@@ -7779,7 +7713,7 @@ const memoize_1 = __webpack_require__(1808);
7779
7713
  const array_1 = __webpack_require__(8112);
7780
7714
 
7781
7715
  function blank(prefix, suffix) {
7782
- return new RegExp(String.raw`^${prefix && prefix.source}(?:\\\s|[^\S\n]+|\n|&(?:${normalize_1.invisibleHTMLEntityNames.join('|')});|<wbr>)?${typeof suffix === 'string' ? suffix.replace(/[*+()\[\]]/g, '\\$&') : suffix.source}`);
7716
+ return new RegExp(String.raw`^(?:${prefix && prefix.source}(?:\\\s|[^\S\n]|\n|&(?:${normalize_1.invisibleHTMLEntityNames.join('|')});|<wbr>)*)?${typeof suffix === 'string' ? suffix.replace(/[*+()\[\]]/g, '\\$&') : suffix.source}`);
7783
7717
  }
7784
7718
 
7785
7719
  exports.blank = blank;
package/markdown.d.ts CHANGED
@@ -28,12 +28,6 @@ export namespace MarkdownParser {
28
28
  readonly autolink?: boolean;
29
29
  };
30
30
  };
31
- readonly state?: {
32
- readonly in?: {
33
- readonly supsub?: boolean;
34
- readonly small?: boolean;
35
- };
36
- };
37
31
  readonly caches?: {
38
32
  readonly code?: Collection<string, HTMLElement>;
39
33
  readonly math?: Collection<string, HTMLElement>;
@@ -987,7 +981,6 @@ export namespace MarkdownParser {
987
981
  HTMLParser.OpenTagParser,
988
982
  HTMLParser.TagParser,
989
983
  HTMLParser.TagParser,
990
- HTMLParser.TagParser,
991
984
  ]> {
992
985
  }
993
986
  export namespace HTMLParser {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.247.0",
3
+ "version": "0.248.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",
@@ -38,7 +38,7 @@
38
38
  "babel-loader": "^8.2.5",
39
39
  "babel-plugin-unassert": "^3.2.0",
40
40
  "concurrently": "^7.2.0",
41
- "eslint": "^8.15.0",
41
+ "eslint": "^8.16.0",
42
42
  "eslint-plugin-redos": "^4.4.0",
43
43
  "eslint-webpack-plugin": "^3.1.1",
44
44
  "glob": "^8.0.3",
@@ -49,7 +49,7 @@
49
49
  "karma-mocha": "^2.0.1",
50
50
  "karma-power-assert": "^1.0.0",
51
51
  "mocha": "^10.0.0",
52
- "npm-check-updates": "^13.0.1",
52
+ "npm-check-updates": "^13.0.3",
53
53
  "semver": "^7.3.7",
54
54
  "spica": "0.0.551",
55
55
  "ts-loader": "^9.3.0",
@@ -19,7 +19,7 @@ export const annotation: AnnotationParser = lazy(() => creator(validate('((', ')
19
19
  //label: true,
20
20
  //link: true,
21
21
  //autolink: true,
22
- }}, state: undefined, delimiters: undefined },
22
+ }}, delimiters: undefined },
23
23
  trimSpaceStart(union([some(inline, ')', /^\\?\n/)]))))),
24
24
  '))'),
25
25
  ns => [html('sup', { class: 'annotation' }, trimNodeEnd(defrag(ns)))]))));
@@ -9,8 +9,8 @@ import { unshift } from 'spica/array';
9
9
  export const deletion: DeletionParser = lazy(() => creator(surround(
10
10
  str('~~'),
11
11
  some(union([
12
- some(inline, blank(/\n?/, '~~')),
13
- open(/^\n?/, some(inline, '~'), true),
12
+ some(inline, blank(/\n/, '~~')),
13
+ open(/^\n/, some(inline, '~'), true),
14
14
  ])),
15
15
  str('~~'), false,
16
16
  ([, bs], rest) => [[html('del', defrag(bs))], rest],
@@ -41,7 +41,7 @@ describe('Unit: parser/inline/html', () => {
41
41
  assert.deepStrictEqual(inspect(parser('</small>')), undefined);
42
42
  assert.deepStrictEqual(inspect(parser('<small/>')), undefined);
43
43
  assert.deepStrictEqual(inspect(parser('<b><b><b>a</b></b></b>')), [['<span class="invalid">&lt;b&gt;<span class="invalid">&lt;b&gt;<span class="invalid">&lt;b&gt;a&lt;/b&gt;</span>&lt;/b&gt;</span>&lt;/b&gt;</span>'], '']);
44
- assert.deepStrictEqual(inspect(parser('<small><small><small>a</small></small></small>')), [['<small><span class="invalid">&lt;small&gt;<span class="invalid">&lt;small&gt;a&lt;/small&gt;</span>&lt;/small&gt;</span></small>'], '']);
44
+ assert.deepStrictEqual(inspect(parser('<small><small><small>a</small></small></small>')), [['<small><small><small>a</small></small></small>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser('<x a="*b*"')), undefined);
46
46
  assert.deepStrictEqual(inspect(parser('<x a="*b*">')), undefined);
47
47
  assert.deepStrictEqual(inspect(parser('<x a="*b*">c')), undefined);
@@ -72,8 +72,8 @@ describe('Unit: parser/inline/html', () => {
72
72
  });
73
73
 
74
74
  it('nest', () => {
75
- assert.deepStrictEqual(inspect(parser('<small><small>a</small></small>')), [['<small><span class="invalid">&lt;small&gt;a&lt;/small&gt;</span></small>'], '']);
76
- assert.deepStrictEqual(inspect(parser('<small>a<small>b</small>c</small>')), [['<small>a<span class="invalid">&lt;small&gt;b&lt;/small&gt;</span>c</small>'], '']);
75
+ assert.deepStrictEqual(inspect(parser('<small><small>a</small></small>')), [['<small><small>a</small></small>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('<small>a<small>b</small>c</small>')), [['<small>a<small>b</small>c</small>'], '']);
77
77
  assert.deepStrictEqual(inspect(parser('<small>`a`</small>')), [['<small><code data-src="`a`">a</code></small>'], '']);
78
78
  });
79
79
 
@@ -1,8 +1,7 @@
1
1
  import { undefined } from 'spica/global';
2
2
  import { isFrozen, ObjectEntries } from 'spica/alias';
3
- import { MarkdownParser } from '../../../markdown';
4
3
  import { HTMLParser } from '../inline';
5
- import { union, some, validate, context, creator, surround, open, match, lazy } from '../../combinator';
4
+ import { union, some, validate, creator, surround, open, match, lazy } from '../../combinator';
6
5
  import { inline } from '../inline';
7
6
  import { str } from '../source';
8
7
  import { startLoose, blank } from '../util';
@@ -31,59 +30,19 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
31
30
  [[h(tag as 'span', attributes('html', [], attrspec[tag], bs))], rest]),
32
31
  ([, tag]) => tags.indexOf(tag), [])),
33
32
  match(
34
- /^(?=<(sup|sub|small)(?=[^\S\n]|>))/,
35
- memoize(
36
- ([, tag]) =>
37
- validate(`<${tag}`, `</${tag}>`,
38
- surround<HTMLParser.TagParser, string>(surround(
39
- str(`<${tag}`), some(attribute), str(/^\s*>/), true),
40
- startLoose(
41
- context((() => {
42
- switch (tag) {
43
- case 'sup':
44
- case 'sub':
45
- return {
46
- state: { in: { supsub: true } },
47
- syntax: { inline: {
48
- annotation: false,
49
- reference: false,
50
- media: false,
51
- }},
52
- };
53
- case 'small':
54
- return {
55
- state: { in: { small: true } },
56
- syntax: { inline: {
57
- media: false,
58
- }},
59
- };
60
- default:
61
- assert(false);
62
- return {};
63
- }
64
- })(),
65
- some(union([
66
- some(inline, blank(/\n?/, `</${tag}>`)),
67
- open(/^\n?/, some(inline, '</'), true),
68
- ]), `</${tag}>`)), `</${tag}>`),
69
- str(`</${tag}>`), false,
70
- ([as, bs, cs], rest, context) =>
71
- [[elem(tag, as, defrag(bs), cs, context)], rest])),
72
- ([, tag]) => tags.indexOf(tag), [])),
73
- match(
74
- /^(?=<(bdo|bdi)(?=[^\S\n]|>))/,
33
+ /^(?=<(sup|sub|small|bdo|bdi)(?=[^\S\n]|>))/,
75
34
  memoize(
76
35
  ([, tag]) =>
77
36
  validate(`<${tag}`, `</${tag}>`,
78
37
  surround<HTMLParser.TagParser, string>(surround(
79
38
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
80
39
  startLoose(some(union([
81
- some(inline, blank(/\n?/, `</${tag}>`)),
82
- open(/^\n?/, some(inline, '</'), true),
40
+ some(inline, blank(/\n/, `</${tag}>`)),
41
+ open(/^\n/, some(inline, `</${tag}>`), true),
83
42
  ]), `</${tag}>`), `</${tag}>`),
84
43
  str(`</${tag}>`), false,
85
- ([as, bs, cs], rest, context) =>
86
- [[elem(tag, as, defrag(bs), cs, context)], rest],
44
+ ([as, bs, cs], rest) =>
45
+ [[elem(tag, as, defrag(bs), cs)], rest],
87
46
  ([as, bs], rest) =>
88
47
  as.length === 1 ? [unshift(as, bs), rest] : undefined)),
89
48
  ([, tag]) => tags.indexOf(tag), [])),
@@ -95,12 +54,12 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
95
54
  surround<HTMLParser.TagParser, string>(surround(
96
55
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
97
56
  startLoose(some(union([
98
- some(inline, blank(/\n?/, `</${tag}>`)),
99
- open(/^\n?/, some(inline, '</'), true),
57
+ some(inline, blank(/\n/, `</${tag}>`)),
58
+ open(/^\n/, some(inline, `</${tag}>`), true),
100
59
  ]), `</${tag}>`), `</${tag}>`),
101
60
  str(`</${tag}>`), false,
102
- ([as, bs, cs], rest, context) =>
103
- [[elem(tag, as, defrag(bs), cs, context)], rest],
61
+ ([as, bs, cs], rest) =>
62
+ [[elem(tag, as, defrag(bs), cs)], rest],
104
63
  ([as, bs], rest) =>
105
64
  as.length === 1 ? [unshift(as, bs), rest] : undefined)),
106
65
  ([, tag]) => tag,
@@ -111,35 +70,16 @@ export const attribute: HTMLParser.TagParser.AttributeParser = union([
111
70
  str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/),
112
71
  ]);
113
72
 
114
- function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[], context: MarkdownParser.Context): HTMLElement {
73
+ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[]): HTMLElement {
115
74
  assert(as.length > 0);
116
75
  assert(as[0][0] === '<' && as[as.length - 1].slice(-1) === '>');
117
76
  assert(bs.length === defrag(bs).length);
118
77
  assert(cs.length === 1);
119
78
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag <${tag}>`, as, bs, cs);
120
- switch (tag) {
121
- case 'sup':
122
- case 'sub':
123
- switch (true) {
124
- case context.state?.in?.supsub:
125
- return invalid('nest', `<${tag}> HTML tag cannot be used in <sup> or <sub> HTML tag`, as, bs, cs);
126
- }
127
- break;
128
- case 'small':
129
- switch (true) {
130
- case context.state?.in?.supsub:
131
- case context.state?.in?.small:
132
- return invalid('nest', `<${tag}> HTML tag cannot be used in <sup>, <sub>, or <small> HTML tag`, as, bs, cs);
133
- }
134
- break;
135
- }
136
79
  const attrs = attributes('html', [], attrspec[tag], as.slice(1, -1));
137
- switch (true) {
138
- case 'data-invalid-syntax' in attrs:
139
- return invalid('attribute', 'Invalid HTML attribute', as, bs, cs);
140
- default:
141
- return h(tag as 'span', attrs, bs);
142
- }
80
+ return 'data-invalid-syntax' in attrs
81
+ ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs)
82
+ : h(tag as 'span', attrs, bs);
143
83
  }
144
84
  function invalid(type: string, message: string, as: (HTMLElement | string)[], bs: (HTMLElement | string)[], cs: (HTMLElement | string)[]): HTMLElement {
145
85
  return h('span', {
@@ -9,8 +9,8 @@ import { unshift } from 'spica/array';
9
9
  export const insertion: InsertionParser = lazy(() => creator(surround(
10
10
  str('++'),
11
11
  some(union([
12
- some(inline, blank(/\n?/, '++')),
13
- open(/^\n?/, some(inline, '+'), true),
12
+ some(inline, blank(/\n/, '++')),
13
+ open(/^\n/, some(inline, '+'), true),
14
14
  ])),
15
15
  str('++'), false,
16
16
  ([, bs], rest) => [[html('ins', defrag(bs))], rest],
@@ -54,13 +54,16 @@ describe('Unit: parser/inline/math', () => {
54
54
  assert.deepStrictEqual(inspect(parser('${a} $')), undefined);
55
55
  assert.deepStrictEqual(inspect(parser('${a{b}$')), undefined);
56
56
  assert.deepStrictEqual(inspect(parser('${a}b}$')), undefined);
57
+ assert.deepStrictEqual(inspect(parser('${a}b$')), undefined);
58
+ assert.deepStrictEqual(inspect(parser('${a}b{c}$')), undefined);
59
+ assert.deepStrictEqual(inspect(parser('${a}{b}$')), undefined);
57
60
  assert.deepStrictEqual(inspect(parser('${$}$')), undefined);
58
61
  assert.deepStrictEqual(inspect(parser('${\\}$')), undefined);
59
62
  assert.deepStrictEqual(inspect(parser('${\n}$')), undefined);
60
63
  assert.deepStrictEqual(inspect(parser('${a\\$\nb}$')), undefined);
61
64
  assert.deepStrictEqual(inspect(parser('${a\\$\\\nb}$')), undefined);
62
65
  assert.deepStrictEqual(inspect(parser('$\\begin{}$')), [['<span class="invalid" translate="no">$\\begin{}$</span>'], '']);
63
- assert.deepStrictEqual(inspect(parser('$\\huge{}$')), [['<span class="invalid" translate="no">$\\huge{}$</span>'], '']);
66
+ assert.deepStrictEqual(inspect(parser('$\\huge0$')), [['<span class="invalid" translate="no">$\\huge0$</span>'], '']);
64
67
  assert.deepStrictEqual(inspect(parser('$\\Begin{}$')), [['<span class="invalid" translate="no">$\\Begin{}$</span>'], '']);
65
68
  assert.deepStrictEqual(inspect(parser('${\\begin}$')), [['<span class="invalid" translate="no">${\\begin}$</span>'], '']);
66
69
  assert.deepStrictEqual(inspect(parser(' ${a}$')), undefined);
@@ -128,9 +131,6 @@ describe('Unit: parser/inline/math', () => {
128
131
  assert.deepStrictEqual(inspect(parser('${\\a}$')), [['<span class="math" translate="no" data-src="${\\a}$">${\\a}$</span>'], '']);
129
132
  assert.deepStrictEqual(inspect(parser('${\\$}$')), [['<span class="math" translate="no" data-src="${\\$}$">${\\$}$</span>'], '']);
130
133
  assert.deepStrictEqual(inspect(parser('${\\\\}$')), [['<span class="math" translate="no" data-src="${\\\\}$">${\\\\}$</span>'], '']);
131
- assert.deepStrictEqual(inspect(parser('${a}b$')), [['<span class="math" translate="no" data-src="${a}b$">${a}b$</span>'], '']);
132
- assert.deepStrictEqual(inspect(parser('${a}b{c}$')), [['<span class="math" translate="no" data-src="${a}b{c}$">${a}b{c}$</span>'], '']);
133
- assert.deepStrictEqual(inspect(parser('${a}{b}$')), [['<span class="math" translate="no" data-src="${a}{b}$">${a}{b}$</span>'], '']);
134
134
  assert.deepStrictEqual(inspect(parser('${あ}$')), [['<span class="math" translate="no" data-src="${あ}$">${あ}$</span>'], '']);
135
135
  });
136
136
 
@@ -4,13 +4,13 @@ import { escsource, str } from '../source';
4
4
  import { html } from 'typed-dom/dom';
5
5
 
6
6
  const syntax = /^(?:[ "([](?!\$)|\\{(?!\$)|\\[\\}$]?|^`|`(?!`)|[!#%&')\x2A-\x5A\]^_\x61-\x7A|~])+/;
7
- const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![0-9a-z])/i;
7
+ const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
8
8
 
9
9
  export const math: MathParser = lazy(() => creator(validate('$', rewrite(
10
10
  union([
11
11
  surround('$', bracket, '$'),
12
12
  surround(
13
- /^\$(?!\s)/,
13
+ /^\$(?![\s{}])/,
14
14
  some(union([
15
15
  bracket,
16
16
  quote,
@@ -28,7 +28,7 @@ export const math: MathParser = lazy(() => creator(validate('$', rewrite(
28
28
  translate: 'no',
29
29
  'data-invalid-syntax': 'math',
30
30
  'data-invalid-type': 'content',
31
- 'data-invalid-message': `"${source.match(forbiddenCommand)![0]}" command is disallowed`,
31
+ 'data-invalid-message': `"${source.match(forbiddenCommand)![0]}" command is forbidden`,
32
32
  },
33
33
  source)
34
34
  ], '']))));
@@ -47,7 +47,7 @@ const quote: MathParser.QuoteParser = lazy(() => creator(surround(
47
47
  some(union([
48
48
  quote,
49
49
  bracket,
50
- focus(/^(?:\\[\\{}$]|`(?!`)|[^`{}"$\n])*/, str(syntax)),
50
+ focus(/^(?:\\[\\{}$]|`(?!`)|[^`{}"$\n\P{ASCII}])*/u, str(syntax)),
51
51
  ])),
52
52
  /^"?/,
53
53
  true)));
@@ -19,7 +19,7 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
19
19
  //label: true,
20
20
  //link: true,
21
21
  //autolink: true,
22
- }}, state: undefined, delimiters: undefined },
22
+ }}, delimiters: undefined },
23
23
  subsequence([
24
24
  abbr,
25
25
  focus(/^\^[^\S\n]*/, source => [['', source], '']),
@@ -10,9 +10,9 @@ import { push } from 'spica/array';
10
10
 
11
11
  export function blank(prefix: '' | RegExp, suffix: string | RegExp): RegExp {
12
12
  return new RegExp(String.raw
13
- `^${
13
+ `^(?:${
14
14
  prefix && prefix.source
15
- }(?:\\\s|[^\S\n]+|\n|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)?${
15
+ }(?:\\\s|[^\S\n]|\n|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)*)?${
16
16
  typeof suffix === 'string' ? suffix.replace(/[*+()\[\]]/g, '\\$&') : suffix.source
17
17
  }`);
18
18
  }