securemark 0.247.1 → 0.248.1

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.1
4
+
5
+ - Fix html parser.
6
+
7
+ ## 0.248.0
8
+
9
+ - Change html parser not to limit nesting patterns of HTML tags.
10
+
11
+ ## 0.247.2
12
+
13
+ - Fix math parser.
14
+
3
15
  ## 0.247.1
4
16
 
5
17
  - Fix 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.1 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.248.1 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"));
@@ -2254,11 +2254,9 @@ const surround_1 = __webpack_require__(7130);
2254
2254
 
2255
2255
  const memoize_1 = __webpack_require__(1808);
2256
2256
 
2257
- const array_1 = __webpack_require__(8112);
2258
-
2259
2257
  function indent(parser, separation = false) {
2260
2258
  return (0, bind_1.bind)((0, block_1.block)((0, match_1.match)(/^(?=(([ \t])\2*))/, (0, memoize_1.memoize)(([, indent]) => (0, some_1.some)((0, line_1.line)((0, surround_1.open)(indent, source => [[unline(source)], '']))), ([, indent]) => indent.length * 2 + +(indent[0] === ' '), [])), separation), (nodes, rest, context) => {
2261
- const result = parser((0, array_1.join)(nodes, '\n'), context);
2259
+ const result = parser(nodes.join('\n'), context);
2262
2260
  return result && (0, parser_1.exec)(result) === '' ? [(0, parser_1.eval)(result), rest] : global_1.undefined;
2263
2261
  });
2264
2262
  }
@@ -5367,7 +5365,6 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0,
5367
5365
 
5368
5366
  }
5369
5367
  },
5370
- state: global_1.undefined,
5371
5368
  delimiters: global_1.undefined
5372
5369
  }, (0, util_1.trimSpaceStart)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, ')', /^\\?\n/)]))))), '))'), ns => [(0, dom_1.html)('sup', {
5373
5370
  class: 'annotation'
@@ -5754,7 +5751,7 @@ const dom_1 = __webpack_require__(3252);
5754
5751
 
5755
5752
  const array_1 = __webpack_require__(8112);
5756
5753
 
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])));
5754
+ 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
5755
 
5759
5756
  /***/ }),
5760
5757
 
@@ -5915,8 +5912,6 @@ const util_1 = __webpack_require__(9437);
5915
5912
 
5916
5913
  const dom_1 = __webpack_require__(3252);
5917
5914
 
5918
- const array_1 = __webpack_require__(8112);
5919
-
5920
5915
  exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[#', ']', '\n', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.fmap)((0, combinator_1.surround)('[#', (0, combinator_1.guard)(context => context.syntax?.inline?.index ?? true, (0, util_1.startTight)((0, combinator_1.context)({
5921
5916
  syntax: {
5922
5917
  inline: {
@@ -5936,7 +5931,7 @@ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combi
5936
5931
  }, el.childNodes)]))));
5937
5932
  const signature = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.fmap)((0, combinator_1.open)('|#', (0, util_1.startTight)((0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'))), ns => [(0, dom_1.html)('span', {
5938
5933
  class: 'indexer',
5939
- 'data-index': (0, indexee_1.identity)((0, array_1.join)(ns)).slice(6)
5934
+ 'data-index': (0, indexee_1.identity)(ns.join('')).slice(6)
5940
5935
  })])));
5941
5936
  const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.some)(source_1.txt, '"'), (0, source_1.str)('"'), true)])));
5942
5937
 
@@ -6076,8 +6071,6 @@ const source_1 = __webpack_require__(6743);
6076
6071
 
6077
6072
  const dom_1 = __webpack_require__(3252);
6078
6073
 
6079
- const array_1 = __webpack_require__(8112);
6080
-
6081
6074
  const body = (0, source_1.str)(/^\$[A-Za-z]*(?:(?:-[A-Za-z][0-9A-Za-z]*)+|-(?:(?:0|[1-9][0-9]*)\.)*(?:0|[1-9][0-9]*)(?![0-9A-Za-z]))/);
6082
6075
  exports.segment = (0, combinator_1.clear)((0, combinator_1.validate)(['[$', '$'], (0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body])));
6083
6076
  exports.label = (0, combinator_1.creator)((0, combinator_1.validate)(['[$', '$'], (0, combinator_1.fmap)((0, combinator_1.guard)(context => context.syntax?.inline?.label ?? true, (0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body])), ([text]) => [(0, dom_1.html)('a', {
@@ -6106,7 +6099,7 @@ function increment(number, position) {
6106
6099
  ms[i] = i < ns.length ? i + 1 < position ? +ns[i] : +ns[i] + 1 : i + 1 < position ? 0 : 1;
6107
6100
  }
6108
6101
 
6109
- return (0, array_1.join)(ms, '.');
6102
+ return ms.join('.');
6110
6103
  }
6111
6104
 
6112
6105
  /***/ }),
@@ -6184,77 +6177,13 @@ const attrspec = {
6184
6177
  };
6185
6178
  Object.setPrototypeOf(attrspec, null);
6186
6179
  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)))])))));
6180
+ 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.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]), ([, tag]) => tags.indexOf(tag), [])), (0, combinator_1.match)(/^(?=<([a-z]+)(?=[^\S\n]|>))/, (0, memoize_1.memoize)(([, 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]), ([, tag]) => tag, new cache_1.Cache(10000)))])))));
6224
6181
  exports.attribute = (0, combinator_1.union)([(0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/)]);
6225
6182
 
6226
- function elem(tag, as, bs, cs, context) {
6183
+ function elem(tag, as, bs, cs) {
6227
6184
  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
6185
  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
- }
6186
+ return 'data-invalid-syntax' in attrs ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs) : (0, dom_1.html)(tag, attrs, bs);
6258
6187
  }
6259
6188
 
6260
6189
  function invalid(type, message, as, bs, cs) {
@@ -6285,7 +6214,7 @@ function attributes(syntax, classes, spec, params) {
6285
6214
  invalid ||= !!spec && !requiredAttributes(spec).every(name => name in attrs);
6286
6215
 
6287
6216
  if (invalid) {
6288
- attrs['class'] = (0, array_1.join)(classes.includes('invalid') ? classes : (0, array_1.unshift)(classes, ['invalid']), ' ');
6217
+ attrs['class'] = (classes.includes('invalid') ? classes : (0, array_1.unshift)(classes, ['invalid'])).join(' ');
6289
6218
  attrs['data-invalid-syntax'] = syntax;
6290
6219
  attrs['data-invalid-type'] = 'argument';
6291
6220
  attrs['data-invalid-message'] = 'Invalid argument';
@@ -6356,7 +6285,7 @@ const dom_1 = __webpack_require__(3252);
6356
6285
 
6357
6286
  const array_1 = __webpack_require__(8112);
6358
6287
 
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])));
6288
+ 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
6289
 
6361
6290
  /***/ }),
6362
6291
 
@@ -6546,7 +6475,7 @@ const dom_1 = __webpack_require__(3252);
6546
6475
 
6547
6476
  const syntax = /^(?:[ "([](?!\$)|\\{(?!\$)|\\[\\}$]?|^`|`(?!`)|[!#%&')\x2A-\x5A\]^_\x61-\x7A|~])+/;
6548
6477
  const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-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, {
6478
+ 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
6479
  caches: {
6551
6480
  math: cache
6552
6481
  } = {}
@@ -6562,7 +6491,7 @@ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combin
6562
6491
  'data-invalid-message': `"${source.match(forbiddenCommand)[0]}" command is forbidden`
6563
6492
  }, source)], '']))));
6564
6493
  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)));
6494
+ 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
6495
 
6567
6496
  /***/ }),
6568
6497
 
@@ -6602,7 +6531,7 @@ const optspec = {
6602
6531
  rel: global_1.undefined
6603
6532
  };
6604
6533
  Object.setPrototypeOf(optspec, null);
6605
- exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['![', '!{'], '}', '\n', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.guard)(context => context.syntax?.inline?.media ?? true, (0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)(/^\[(?!\s*\\\s)/, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', /^\\?\n/), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))]))), ([as, bs]) => bs ? [[(0, array_1.join)(as).trim() || (0, array_1.join)(as)], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6534
+ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['![', '!{'], '}', '\n', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.guard)(context => context.syntax?.inline?.media ?? true, (0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)(/^\[(?!\s*\\\s)/, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', /^\\?\n/), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))]))), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6606
6535
  const INSECURE_URI = params.shift();
6607
6536
  const url = new url_1.ReadonlyURL((0, link_1.resolve)(INSECURE_URI, context.host ?? global_1.location, context.url ?? context.host ?? global_1.location), context.host?.href || global_1.location.href);
6608
6537
  let cache;
@@ -6617,7 +6546,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, c
6617
6546
  if (context.syntax?.inline?.link === false || cache && cache.tagName !== 'IMG') return [[el], rest];
6618
6547
  return (0, combinator_1.fmap)(link_1.link, ([link]) => [(0, dom_1.define)(link, {
6619
6548
  target: '_blank'
6620
- }, [el])])(`{ ${INSECURE_URI}${(0, array_1.join)(params)} }${rest}`, context);
6549
+ }, [el])])(`{ ${INSECURE_URI}${params.join('')} }${rest}`, context);
6621
6550
  }))));
6622
6551
  const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"'), (0, source_1.str)('"'), true)]));
6623
6552
  const option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*x[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` width="${opt.slice(1).split('x')[0]}"`, ` height="${opt.slice(1).split('x')[1]}"`]), (0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*:[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` aspect-ratio="${opt.slice(1).split(':').join('/')}"`]), link_1.option]);
@@ -6700,7 +6629,6 @@ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, c
6700
6629
 
6701
6630
  }
6702
6631
  },
6703
- state: global_1.undefined,
6704
6632
  delimiters: global_1.undefined
6705
6633
  }, (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
6634
  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)]));
@@ -6760,7 +6688,7 @@ exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combin
6760
6688
  return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)((0, array_1.push)([...texts[0]].reduce((acc, _, i, texts) => (0, array_1.push)(acc, (0, array_1.unshift)([texts[i]], i < rubies.length && rubies[i] ? [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies[i]), (0, dom_1.html)('rp', ')')] : [(0, dom_1.html)('rt')])), []), tail)))], rest];
6761
6689
 
6762
6690
  default:
6763
- return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)([(0, array_1.join)(texts, ' ')], [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', (0, array_1.join)(rubies, ' ').trim()), (0, dom_1.html)('rp', ')')]), tail)))], rest];
6691
+ return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)([texts.join(' ')], [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies.join(' ').trim()), (0, dom_1.html)('rp', ')')]), tail)))], rest];
6764
6692
  }
6765
6693
  }))));
6766
6694
  const text = (0, combinator_1.creator)((source, context) => {
@@ -6797,7 +6725,7 @@ const text = (0, combinator_1.creator)((source, context) => {
6797
6725
  }
6798
6726
  }
6799
6727
 
6800
- return (0, array_1.join)(acc).trimStart() ? [[acc], ''] : global_1.undefined;
6728
+ return acc.join('').trimStart() ? [[acc], ''] : global_1.undefined;
6801
6729
  });
6802
6730
 
6803
6731
  function attributes(texts, rubies) {
@@ -7092,16 +7020,16 @@ function* figure(target, footnotes, opts = {}) {
7092
7020
  }
7093
7021
 
7094
7022
  const group = label.split('-', 1)[0];
7095
- let number = (0, label_1.number)(label, numbers.has(group) && !(0, label_1.isFixed)(label) ? (0, array_1.join)(numbers.get(group).split('.').slice(0, bases.length), '.') : base);
7023
+ let number = (0, label_1.number)(label, numbers.has(group) && !(0, label_1.isFixed)(label) ? numbers.get(group).split('.').slice(0, bases.length).join('.') : base);
7096
7024
 
7097
7025
  if (number.endsWith('.0')) {
7098
7026
  if (group !== '$' || tagName === 'FIGURE' && def.firstChild) continue;
7099
7027
 
7100
7028
  if (number.startsWith('0.')) {
7101
- number = (0, array_1.join)(index.slice(0).reduce((ns, _, i, xs) => {
7029
+ number = index.slice(0).reduce((ns, _, i, xs) => {
7102
7030
  i === ns.length ? xs.length = i : ns[i] = +ns[i] > +xs[i] ? ns[i] : +ns[i] === 0 ? xs[i] : `${+xs[i] + 1}`;
7103
7031
  return ns;
7104
- }, number.split('.')), '.');
7032
+ }, number.split('.')).join('.');
7105
7033
  }
7106
7034
 
7107
7035
  base = number;
@@ -7180,7 +7108,7 @@ const messages = {
7180
7108
 
7181
7109
  function increment(bases, el) {
7182
7110
  const index = (+el.tagName[1] - 1 || 1) - 1;
7183
- return index + 1 < bases.length ? (0, array_1.join)(bases.slice(0, index + 2).map((v, i) => {
7111
+ return index + 1 < bases.length ? bases.slice(0, index + 2).map((v, i) => {
7184
7112
  switch (true) {
7185
7113
  case i < index:
7186
7114
  return v;
@@ -7191,7 +7119,7 @@ function increment(bases, el) {
7191
7119
  default:
7192
7120
  return 0;
7193
7121
  }
7194
- }), '.') : '';
7122
+ }).join('.') : '';
7195
7123
  }
7196
7124
 
7197
7125
  function capitalize(label) {
@@ -7779,7 +7707,7 @@ const memoize_1 = __webpack_require__(1808);
7779
7707
  const array_1 = __webpack_require__(8112);
7780
7708
 
7781
7709
  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}`);
7710
+ 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
7711
  }
7784
7712
 
7785
7713
  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.1",
3
+ "version": "0.248.1",
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",
@@ -7,7 +7,6 @@ import { bind } from '../monad/bind';
7
7
  import { match } from './match';
8
8
  import { open } from './surround';
9
9
  import { memoize } from 'spica/memoize';
10
- import { join } from 'spica/array';
11
10
 
12
11
  export function indent<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
13
12
  export function indent<T>(parser: Parser<T>, separation = false): Parser<T> {
@@ -19,7 +18,7 @@ export function indent<T>(parser: Parser<T>, separation = false): Parser<T> {
19
18
  some(line(open(indent, source => [[unline(source)], '']))),
20
19
  ([, indent]) => indent.length * 2 + +(indent[0] === ' '), [])), separation),
21
20
  (nodes, rest, context) => {
22
- const result = parser(join(nodes, '\n'), context);
21
+ const result = parser(nodes.join('\n'), context);
23
22
  return result && exec(result) === ''
24
23
  ? [eval(result), rest]
25
24
  : undefined;
@@ -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],
@@ -6,7 +6,6 @@ import { indexee, identity } from './indexee';
6
6
  import { txt, str, stropt } from '../../source';
7
7
  import { startTight, trimNodeEnd } from '../../util';
8
8
  import { html, define, defrag } from 'typed-dom/dom';
9
- import { join } from 'spica/array';
10
9
 
11
10
  import IndexParser = ExtensionParser.IndexParser;
12
11
 
@@ -44,7 +43,7 @@ const signature: IndexParser.SignatureParser = lazy(() => creator(fmap(open(
44
43
  '|#',
45
44
  startTight(some(union([bracket, txt]), ']'))),
46
45
  ns => [
47
- html('span', { class: 'indexer', 'data-index': identity(join(ns)).slice(6) }),
46
+ html('span', { class: 'indexer', 'data-index': identity(ns.join('')).slice(6) }),
48
47
  ])));
49
48
 
50
49
  const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creator(union([
@@ -3,7 +3,6 @@ import { ExtensionParser } from '../../inline';
3
3
  import { union, validate, guard, creator, surround, clear, fmap } from '../../../combinator';
4
4
  import { str } from '../../source';
5
5
  import { html } from 'typed-dom/dom';
6
- import { join } from 'spica/array';
7
6
 
8
7
  const body = str(/^\$[A-Za-z]*(?:(?:-[A-Za-z][0-9A-Za-z]*)+|-(?:(?:0|[1-9][0-9]*)\.)*(?:0|[1-9][0-9]*)(?![0-9A-Za-z]))/);
9
8
 
@@ -48,5 +47,5 @@ function increment(number: string, position: number): string {
48
47
  ? 0
49
48
  : 1;
50
49
  }
51
- return join(ms, '.');
50
+ return ms.join('.');
52
51
  }
@@ -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,15 +1,14 @@
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';
9
8
  import { html as h, defrag } from 'typed-dom/dom';
10
9
  import { memoize } from 'spica/memoize';
11
10
  import { Cache } from 'spica/cache';
12
- import { unshift, push, splice, join } from 'spica/array';
11
+ import { unshift, push, splice } from 'spica/array';
13
12
 
14
13
  const tags = Object.freeze(['wbr', 'sup', 'sub', 'small', 'bdo', 'bdi']);
15
14
  const attrspec = {
@@ -31,78 +30,32 @@ 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]|>))/,
33
+ /^(?=<(sup|sub|small|bdo|bdi)(?=[^\S\n]|>))/,
35
34
  memoize(
36
35
  ([, 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]|>))/,
75
- memoize(
76
- ([, tag]) =>
77
- validate(`<${tag}`, `</${tag}>`,
78
36
  surround<HTMLParser.TagParser, string>(surround(
79
37
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
80
38
  startLoose(some(union([
81
- some(inline, blank(/\n?/, `</${tag}>`)),
82
- open(/^\n?/, some(inline, '</'), true),
39
+ some(inline, blank(/\n/, `</${tag}>`)),
40
+ open(/^\n/, some(inline, `</${tag}>`), true),
83
41
  ]), `</${tag}>`), `</${tag}>`),
84
42
  str(`</${tag}>`), false,
85
- ([as, bs, cs], rest, context) =>
86
- [[elem(tag, as, defrag(bs), cs, context)], rest],
87
- ([as, bs], rest) =>
88
- as.length === 1 ? [unshift(as, bs), rest] : undefined)),
43
+ ([as, bs, cs], rest) =>
44
+ [[elem(tag, as, defrag(bs), cs)], rest]),
89
45
  ([, tag]) => tags.indexOf(tag), [])),
90
46
  match(
91
47
  /^(?=<([a-z]+)(?=[^\S\n]|>))/,
92
48
  memoize(
93
49
  ([, tag]) =>
94
- validate(`<${tag}`, `</${tag}>`,
95
50
  surround<HTMLParser.TagParser, string>(surround(
96
51
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
97
52
  startLoose(some(union([
98
- some(inline, blank(/\n?/, `</${tag}>`)),
99
- open(/^\n?/, some(inline, '</'), true),
53
+ some(inline, blank(/\n/, `</${tag}>`)),
54
+ open(/^\n/, some(inline, `</${tag}>`), true),
100
55
  ]), `</${tag}>`), `</${tag}>`),
101
56
  str(`</${tag}>`), false,
102
- ([as, bs, cs], rest, context) =>
103
- [[elem(tag, as, defrag(bs), cs, context)], rest],
104
- ([as, bs], rest) =>
105
- as.length === 1 ? [unshift(as, bs), rest] : undefined)),
57
+ ([as, bs, cs], rest) =>
58
+ [[elem(tag, as, defrag(bs), cs)], rest]),
106
59
  ([, tag]) => tag,
107
60
  new Cache(10000))),
108
61
  ])))));
@@ -111,35 +64,16 @@ export const attribute: HTMLParser.TagParser.AttributeParser = union([
111
64
  str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/),
112
65
  ]);
113
66
 
114
- function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[], context: MarkdownParser.Context): HTMLElement {
67
+ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[]): HTMLElement {
115
68
  assert(as.length > 0);
116
69
  assert(as[0][0] === '<' && as[as.length - 1].slice(-1) === '>');
117
70
  assert(bs.length === defrag(bs).length);
118
71
  assert(cs.length === 1);
119
72
  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
73
  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
- }
74
+ return 'data-invalid-syntax' in attrs
75
+ ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs)
76
+ : h(tag as 'span', attrs, bs);
143
77
  }
144
78
  function invalid(type: string, message: string, as: (HTMLElement | string)[], bs: (HTMLElement | string)[], cs: (HTMLElement | string)[]): HTMLElement {
145
79
  return h('span', {
@@ -182,7 +116,7 @@ export function attributes(
182
116
  }
183
117
  invalid ||= !!spec && !requiredAttributes(spec).every(name => name in attrs);
184
118
  if (invalid) {
185
- attrs['class'] = join(classes.includes('invalid') ? classes : unshift(classes, ['invalid']), ' ');
119
+ attrs['class'] = (classes.includes('invalid') ? classes : unshift(classes, ['invalid'])).join(' ');
186
120
  attrs['data-invalid-syntax'] = syntax;
187
121
  attrs['data-invalid-type'] = 'argument';
188
122
  attrs['data-invalid-message'] = 'Invalid argument';
@@ -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,6 +54,9 @@ 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);
@@ -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
 
@@ -10,7 +10,7 @@ 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,
@@ -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)));
@@ -7,7 +7,7 @@ import { unsafehtmlentity } from './htmlentity';
7
7
  import { txt, str } from '../source';
8
8
  import { html, define } from 'typed-dom/dom';
9
9
  import { ReadonlyURL } from 'spica/url';
10
- import { unshift, push, join } from 'spica/array';
10
+ import { unshift, push } from 'spica/array';
11
11
 
12
12
  const optspec = {
13
13
  'width': [],
@@ -28,7 +28,7 @@ export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'],
28
28
  true)),
29
29
  dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
30
30
  ]))),
31
- ([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
31
+ ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]),
32
32
  ([[text]]) => text === '' || text.trim() !== ''),
33
33
  ([[text], params], rest, context) => {
34
34
  assert(text === text.trim());
@@ -52,7 +52,7 @@ export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'],
52
52
  return fmap(
53
53
  link as MediaParser,
54
54
  ([link]) => [define(link, { target: '_blank' }, [el])])
55
- (`{ ${INSECURE_URI}${join(params)} }${rest}`, context);
55
+ (`{ ${INSECURE_URI}${params.join('')} }${rest}`, context);
56
56
  }))));
57
57
 
58
58
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => union([
@@ -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], '']),
@@ -6,7 +6,7 @@ import { unsafehtmlentity } from './htmlentity';
6
6
  import { text as txt } from '../source';
7
7
  import { isStartTightNodes } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
- import { unshift, push, join } from 'spica/array';
9
+ import { unshift, push } from 'spica/array';
10
10
 
11
11
  export const ruby: RubyParser = lazy(() => creator(validate('[', ')', '\n', bind(verify(
12
12
  sequence([
@@ -39,8 +39,8 @@ export const ruby: RubyParser = lazy(() => creator(validate('[', ')', '\n', bind
39
39
  default:
40
40
  assert(rubies.length > 0);
41
41
  return [[html('ruby', attributes(texts, rubies), defrag(push(unshift(
42
- [join(texts, ' ')],
43
- [html('rp', '('), html('rt', join(rubies, ' ').trim()), html('rp', ')')]), tail)))
42
+ [texts.join(' ')],
43
+ [html('rp', '('), html('rt', rubies.join(' ').trim()), html('rp', ')')]), tail)))
44
44
  ], rest];
45
45
  }
46
46
  }))));
@@ -74,7 +74,7 @@ const text: RubyParser.TextParser = creator((source, context) => {
74
74
  }
75
75
  }
76
76
  }
77
- return join(acc).trimStart()
77
+ return acc.join('').trimStart()
78
78
  ? [[acc], '']
79
79
  : undefined;
80
80
  });
@@ -157,6 +157,7 @@ describe('Unit: parser/inline', () => {
157
157
  assert.deepStrictEqual(inspect(parser('<http://host>')), [['<', '<a href="http://host" target="_blank">http://host</a>', '>'], '']);
158
158
  assert.deepStrictEqual(inspect(parser('<<small>a<</small>')), [['<', '<small>a&lt;</small>'], '']);
159
159
  assert.deepStrictEqual(inspect(parser('<sup><sub>a</sub>')), [['<', 'sup', '>', '<sub>a</sub>'], '']);
160
+ assert.deepStrictEqual(inspect(parser('*<small>*`</small>`')), [['<em>&lt;small&gt;</em>', '<code data-src="`</small>`">&lt;/small&gt;</code>'], '']);
160
161
  assert.deepStrictEqual(inspect(parser('[~http://host')), [['[', '~', '<a href="http://host" target="_blank">http://host</a>'], '']);
161
162
  assert.deepStrictEqual(inspect(parser('[~a@b')), [['[', '~', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
162
163
  assert.deepStrictEqual(inspect(parser('[~~a~~]')), [['[', '<del>a</del>', ']'], '']);
@@ -2,7 +2,7 @@ import { Infinity, Set, Map } from 'spica/global';
2
2
  import { number as calculate, isFixed } from '../inline/extension/label';
3
3
  import { define } from 'typed-dom/dom';
4
4
  import { MultiMap } from 'spica/multimap';
5
- import { push, join } from 'spica/array';
5
+ import { push } from 'spica/array';
6
6
 
7
7
  export function* figure(
8
8
  target: ParentNode & Node,
@@ -85,7 +85,7 @@ export function* figure(
85
85
  let number = calculate(
86
86
  label,
87
87
  numbers.has(group) && !isFixed(label)
88
- ? join(numbers.get(group)!.split('.').slice(0, bases.length), '.')
88
+ ? numbers.get(group)!.split('.').slice(0, bases.length).join('.')
89
89
  : base);
90
90
  assert(def.matches('figure') || number.endsWith('.0'));
91
91
  if (number.endsWith('.0')) {
@@ -94,19 +94,18 @@ export function* figure(
94
94
  if (group !== '$' || tagName === 'FIGURE' && def.firstChild) continue;
95
95
  if (number.startsWith('0.')) {
96
96
  assert(number.endsWith('.0'));
97
- number = join(
98
- index.slice(0)
99
- .reduce((ns, _, i, xs) => {
100
- i === ns.length
101
- ? xs.length = i
102
- : ns[i] = +ns[i] > +xs[i]
103
- ? ns[i]
104
- : +ns[i] === 0
105
- ? xs[i]
106
- : `${+xs[i] + 1}`;
107
- return ns;
108
- }, number.split('.')),
109
- '.');
97
+ number = index.slice(0)
98
+ .reduce((ns, _, i, xs) => {
99
+ i === ns.length
100
+ ? xs.length = i
101
+ : ns[i] = +ns[i] > +xs[i]
102
+ ? ns[i]
103
+ : +ns[i] === 0
104
+ ? xs[i]
105
+ : `${+xs[i] + 1}`;
106
+ return ns;
107
+ }, number.split('.'))
108
+ .join('.');
110
109
  }
111
110
  base = number;
112
111
  bases = index = base.split('.');
@@ -184,8 +183,8 @@ function increment(bases: readonly string[], el: HTMLHeadingElement): string {
184
183
  const index = (+el.tagName[1] - 1 || 1) - 1;
185
184
  assert(index >= 0);
186
185
  return index + 1 < bases.length
187
- ? join(
188
- bases.slice(0, index + 2).map((v, i) => {
186
+ ? bases.slice(0, index + 2)
187
+ .map((v, i) => {
189
188
  switch (true) {
190
189
  case i < index:
191
190
  return v;
@@ -194,8 +193,8 @@ function increment(bases: readonly string[], el: HTMLHeadingElement): string {
194
193
  default:
195
194
  return 0;
196
195
  }
197
- }),
198
- '.')
196
+ })
197
+ .join('.')
199
198
  : '';
200
199
  }
201
200
 
@@ -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
  }