securemark 0.261.1 → 0.262.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +1228 -665
  3. package/package.json +9 -9
  4. package/src/combinator/control/constraint/contract.ts +6 -8
  5. package/src/combinator/data/parser/context/memo.ts +1 -1
  6. package/src/combinator/data/parser/inits.ts +1 -1
  7. package/src/combinator/data/parser/sequence.ts +1 -1
  8. package/src/combinator/data/parser/union.ts +12 -7
  9. package/src/debug.test.ts +3 -3
  10. package/src/parser/api/bind.ts +2 -2
  11. package/src/parser/api/parse.test.ts +1 -1
  12. package/src/parser/api/parse.ts +1 -1
  13. package/src/parser/block/blockquote.test.ts +31 -31
  14. package/src/parser/block/blockquote.ts +1 -1
  15. package/src/parser/block/dlist.ts +1 -1
  16. package/src/parser/block/extension/aside.test.ts +3 -3
  17. package/src/parser/block/extension/aside.ts +1 -0
  18. package/src/parser/block/extension/example.test.ts +11 -11
  19. package/src/parser/block/extension/example.ts +1 -1
  20. package/src/parser/block/extension/fig.test.ts +5 -5
  21. package/src/parser/block/extension/figure.test.ts +2 -2
  22. package/src/parser/block/extension/figure.ts +1 -1
  23. package/src/parser/block/extension/message.ts +1 -1
  24. package/src/parser/block/extension/table.ts +1 -1
  25. package/src/parser/block/olist.ts +5 -7
  26. package/src/parser/block/reply.ts +1 -1
  27. package/src/parser/block/table.ts +8 -8
  28. package/src/parser/block/ulist.ts +1 -1
  29. package/src/parser/block.ts +1 -1
  30. package/src/parser/inline/bracket.ts +1 -1
  31. package/src/parser/inline/comment.ts +1 -1
  32. package/src/parser/inline/deletion.ts +1 -1
  33. package/src/parser/inline/emphasis.ts +1 -1
  34. package/src/parser/inline/extension/indexee.ts +9 -8
  35. package/src/parser/inline/extension/placeholder.ts +1 -1
  36. package/src/parser/inline/html.ts +1 -1
  37. package/src/parser/inline/insertion.ts +1 -1
  38. package/src/parser/inline/link.ts +1 -1
  39. package/src/parser/inline/mark.ts +1 -1
  40. package/src/parser/inline/media.ts +1 -1
  41. package/src/parser/inline/ruby.ts +1 -1
  42. package/src/parser/inline/strong.ts +1 -1
  43. package/src/parser/inline/template.ts +1 -1
  44. package/src/parser/locale.test.ts +1 -1
  45. package/src/parser/locale.ts +5 -4
  46. package/src/parser/processor/figure.test.ts +3 -3
  47. package/src/parser/processor/figure.ts +10 -8
  48. package/src/parser/processor/footnote.test.ts +2 -2
  49. package/src/parser/processor/footnote.ts +17 -12
  50. package/src/renderer/render.ts +3 -3
  51. package/src/util/info.ts +7 -5
  52. package/src/util/quote.ts +14 -12
  53. package/src/util/toc.ts +14 -8
@@ -5,8 +5,8 @@ import { ilist_ } from './ilist';
5
5
  import { inline, indexer, indexee } from '../inline';
6
6
  import { State } from '../context';
7
7
  import { trimBlank } from '../visibility';
8
- import { html, defrag } from 'typed-dom/dom';
9
8
  import { unshift } from 'spica/array';
9
+ import { html, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const ulist: UListParser = lazy(() => block(validate(
12
12
  /^-(?=[^\S\n]|\n[^\S\n]*\S)/,
@@ -16,8 +16,8 @@ import { sidefence } from './block/sidefence';
16
16
  import { blockquote } from './block/blockquote';
17
17
  import { reply } from './block/reply';
18
18
  import { paragraph } from './block/paragraph';
19
- import { html } from 'typed-dom/dom';
20
19
  import { rnd0Z } from 'spica/random';
20
+ import { html } from 'typed-dom/dom';
21
21
 
22
22
  export import BlockParser = MarkdownParser.BlockParser;
23
23
  export import HorizontalRuleParser = BlockParser.HorizontalRuleParser;
@@ -4,8 +4,8 @@ import { union, some, syntax, surround, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
6
  import { Syntax, State } from '../context';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift, push } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
11
11
 
@@ -3,9 +3,9 @@ import { union, some, syntax, validate, surround, open, close, match, lazy } fro
3
3
  import { inline } from '../inline';
4
4
  import { text, str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
- import { html, defrag } from 'typed-dom/dom';
7
6
  import { memoize } from 'spica/memoize';
8
7
  import { unshift, push } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const comment: CommentParser = lazy(() => validate('[%', syntax(Syntax.none, 4, 1, State.none, match(
11
11
  /^\[(%+)\s/,
@@ -4,8 +4,8 @@ import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
6
  import { blankWith } from '../visibility';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const deletion: DeletionParser = lazy(() => surround(
11
11
  str('~~', '~'),
@@ -4,8 +4,8 @@ import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
6
  import { startTight, blankWith } from '../visibility';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const emphasis: EmphasisParser = lazy(() => surround(
11
11
  str('_', '_'),
@@ -3,7 +3,7 @@ import { MarkdownParser } from '../../../../markdown';
3
3
  import { Parser } from '../../../combinator/data/parser';
4
4
  import { fmap } from '../../../combinator';
5
5
  import { define } from 'typed-dom/dom';
6
- import { duffEach } from 'spica/duff';
6
+ import { querySelectorAll } from 'typed-dom/query';
7
7
 
8
8
  export function indexee<P extends Parser<unknown, MarkdownParser.Context>>(parser: P, optional?: boolean): P;
9
9
  export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>, optional?: boolean): Parser<HTMLElement> {
@@ -28,32 +28,33 @@ export function text(source: HTMLElement | DocumentFragment, optional = false):
28
28
  if (index) return index;
29
29
  assert(!source.querySelector('.annotation, br'));
30
30
  const target = source.cloneNode(true) as typeof source;
31
- duffEach(target.querySelectorAll('code[data-src], .math[data-src], .comment, rt, rp, .reference, .checkbox, ul, ol'), el => {
31
+ for (let es = querySelectorAll(target, 'code[data-src], .math[data-src], .comment, rt, rp, .reference, .checkbox, ul, ol'), i = 0; i < es.length; ++i) {
32
+ const el = es[i];
32
33
  switch (el.tagName) {
33
34
  case 'CODE':
34
35
  define(el, el.getAttribute('data-src')!);
35
- return;
36
+ continue;
36
37
  case 'RT':
37
38
  case 'RP':
38
39
  case 'UL':
39
40
  case 'OL':
40
41
  el.remove();
41
- return;
42
+ continue;
42
43
  }
43
44
  switch (el.className) {
44
45
  case 'math':
45
46
  define(el, el.getAttribute('data-src')!);
46
- return;
47
+ continue;
47
48
  case 'comment':
48
49
  case 'checkbox':
49
50
  el.remove();
50
- return;
51
+ continue;
51
52
  case 'reference':
52
53
  assert(el.firstElementChild?.hasAttribute('hidden'));
53
54
  el.firstChild!.remove();
54
- return;
55
+ continue;
55
56
  }
56
- });
57
+ }
57
58
  // Better:
58
59
  //return target.innerText;
59
60
  return target.textContent!;
@@ -4,8 +4,8 @@ import { inline } from '../../inline';
4
4
  import { str } from '../../source';
5
5
  import { Syntax, State } from '../../context';
6
6
  import { startTight } from '../../visibility';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  // Don't use the symbols already used: !#$%@&*+~=
11
11
 
@@ -5,10 +5,10 @@ import { inline } from '../inline';
5
5
  import { str } from '../source';
6
6
  import { Syntax, State } from '../context';
7
7
  import { isStartLooseNodes, blankWith } from '../visibility';
8
- import { html as h, defrag } from 'typed-dom/dom';
9
8
  import { memoize } from 'spica/memoize';
10
9
  import { Cache } from 'spica/cache';
11
10
  import { unshift, push, splice } from 'spica/array';
11
+ import { html as h, defrag } from 'typed-dom/dom';
12
12
 
13
13
  const tags = Object.freeze(['bdo', 'bdi']);
14
14
  const attrspecs = {
@@ -4,8 +4,8 @@ import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
6
  import { blankWith } from '../visibility';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() => surround(
11
11
  str('++', '+'),
@@ -10,8 +10,8 @@ import { unescsource, str } from '../source';
10
10
  import { Syntax, State } from '../context';
11
11
  import { trimNode } from '../visibility';
12
12
  import { stringify } from '../util';
13
- import { html, define, defrag } from 'typed-dom/dom';
14
13
  import { ReadonlyURL } from 'spica/url';
14
+ import { html, define, defrag } from 'typed-dom/dom';
15
15
 
16
16
  const optspec = {
17
17
  rel: ['nofollow'],
@@ -4,8 +4,8 @@ import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { startTight, blankWith } from '../visibility';
6
6
  import { Syntax, State } from '../context';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const mark: MarkParser = lazy(() => surround(
11
11
  str('==', '='),
@@ -6,9 +6,9 @@ import { attributes } from './html';
6
6
  import { unsafehtmlentity } from './htmlentity';
7
7
  import { txt, str } from '../source';
8
8
  import { Syntax, State } from '../context';
9
- import { html, define } from 'typed-dom/dom';
10
9
  import { ReadonlyURL } from 'spica/url';
11
10
  import { unshift, push } from 'spica/array';
11
+ import { html, define } from 'typed-dom/dom';
12
12
 
13
13
  const optspec = {
14
14
  'width': [],
@@ -6,8 +6,8 @@ import { unsafehtmlentity } from './htmlentity';
6
6
  import { text as txt, str } from '../source';
7
7
  import { Syntax, State } from '../context';
8
8
  import { isStartTightNodes } from '../visibility';
9
- import { html, defrag } from 'typed-dom/dom';
10
9
  import { unshift, push } from 'spica/array';
10
+ import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const ruby: RubyParser = lazy(() => validate('[', syntax(Syntax.ruby, 2, 1, State.all, fmap(verify(fmap(
13
13
  sequence([
@@ -4,8 +4,8 @@ import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
6
  import { startTight, blankWith } from '../visibility';
7
- import { html, defrag } from 'typed-dom/dom';
8
7
  import { unshift } from 'spica/array';
8
+ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const strong: StrongParser = lazy(() => surround(
11
11
  str('*', '*'),
@@ -3,8 +3,8 @@ import { TemplateParser } from '../inline';
3
3
  import { union, some, syntax, creation, precedence, surround, lazy } from '../../combinator';
4
4
  import { escsource, str } from '../source';
5
5
  import { Syntax, State } from '../context';
6
- import { html } from 'typed-dom/dom';
7
6
  import { unshift } from 'spica/array';
7
+ import { html } from 'typed-dom/dom';
8
8
 
9
9
  export const template: TemplateParser = lazy(() => surround(
10
10
  '{{', syntax(Syntax.none, 2, 1, State.all, some(union([bracket, escsource]), '}')), '}}', true,
@@ -10,7 +10,7 @@ describe('Unit: parser/locale', () => {
10
10
  assert.deepStrictEqual(inspect(parser('。\\\n0')), [['<p>。<span class="linebreak"></span>0</p>'], '']);
11
11
  assert.deepStrictEqual(inspect(parser('。 \\\n0')), [['<p>。<span class="linebreak"></span>0</p>'], '']);
12
12
  assert.deepStrictEqual(inspect(parser('_。_\\\n0')), [['<p><em>。</em><span class="linebreak"></span>0</p>'], '']);
13
- assert.deepStrictEqual(inspect(parser('!> 。\\\n0')), [['<blockquote><section><p>。<span class="linebreak"></span>0</p><ol class="references"></ol></section></blockquote>'], '']);
13
+ assert.deepStrictEqual(inspect(parser('!> 。\\\n0')), [['<blockquote><section><p>。<span class="linebreak"></span>0</p><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
14
14
  assert.deepStrictEqual(inspect(parser('[。](a)\\\n0')), [['<p><ruby>。<rp>(</rp><rt>a</rt><rp>)</rp></ruby><span class="linebreak"></span>0</p>'], '']);
15
15
  assert.deepStrictEqual(inspect(parser('[。 ](a )\\\n0')), [['<p><ruby>。<rp>(</rp><rt>a</rt><rp>)</rp></ruby><span class="linebreak"></span>0</p>'], '']);
16
16
  assert.deepStrictEqual(inspect(parser('。<wbr>\\\n0')), [['<p>。<wbr><span class="linebreak"></span>0</p>'], '']);
@@ -2,7 +2,7 @@ import { Parser } from '../combinator/data/parser';
2
2
  import { fmap } from '../combinator';
3
3
  import { japanese } from './locale/ja';
4
4
  import { html } from 'typed-dom/dom';
5
- import { duffEach } from 'spica/duff';
5
+ import { querySelectorAll } from 'typed-dom/query';
6
6
 
7
7
  export function localize<P extends Parser<HTMLElement | string>>(parser: P): P;
8
8
  export function localize(parser: Parser<HTMLElement | string>): Parser<HTMLElement | string> {
@@ -11,11 +11,12 @@ export function localize(parser: Parser<HTMLElement | string>): Parser<HTMLEleme
11
11
  const el = ns.length === 1 && typeof ns[0] === 'object'
12
12
  ? ns[0]
13
13
  : html('div', ns);
14
- duffEach(el.querySelectorAll('.linebreak:not(:empty)'), el => {
14
+ for (let es = querySelectorAll(el, '.linebreak:not(:empty)'), i = 0; i < es.length; ++i) {
15
+ const el = es[i];
15
16
  assert(el.firstChild!.textContent === ' ');
16
- if (!check(el)) return;
17
+ if (!check(el)) continue;
17
18
  el.firstChild!.remove();
18
- });
19
+ }
19
20
  return ns;
20
21
  });
21
22
  }
@@ -117,8 +117,8 @@ describe('Unit: parser/processor/figure', () => {
117
117
  assert.deepStrictEqual(
118
118
  [...target.children].map(el => el.outerHTML),
119
119
  [
120
- '<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><ol class="references"></ol></section></blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><ol class="references"></ol></section></blockquote>',
121
- '<aside class="example" data-type="markdown"><pre translate="no">~~~figure $test-a\n&gt; \n\n~~~\n\n$test-a</pre><hr><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><p><a class="label disabled" data-label="test-a">Test 1</a></p><ol class="references"></ol></section></aside>',
120
+ '<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote>',
121
+ '<aside class="example" data-type="markdown"><pre translate="no">~~~figure $test-a\n&gt; \n\n~~~\n\n$test-a</pre><hr><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><p><a class="label disabled" data-label="test-a">Test 1</a></p><h2>References</h2><ol class="references"></ol></section></aside>',
122
122
  '<figure data-type="quote" data-label="test-b" data-group="test" data-number="1" id="label:test-b"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>',
123
123
  '<figure data-type="quote" data-label="test-a" data-group="test" data-number="2" id="label:test-a"><figcaption><span class="figindex">Test 2. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>',
124
124
  ]);
@@ -173,7 +173,7 @@ describe('Unit: parser/processor/figure', () => {
173
173
  '<h2 id="index:0">0</h2>',
174
174
  '<figure data-type="quote" data-label="test-1" data-group="test" data-number="1" id="label:test-1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>',
175
175
  '<h2 id="index:0">0</h2>',
176
- '<blockquote><section><h2>0</h2><ol class="references"></ol></section></blockquote>',
176
+ '<blockquote><section><h2>0</h2><h2>References</h2><ol class="references"></ol></section></blockquote>',
177
177
  '<figure data-type="quote" data-label="test-b" data-group="test" data-number="2.1" id="label:test-b"><figcaption><span class="figindex">Test 2.1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>',
178
178
  '<h2 id="index:0">0</h2>',
179
179
  '<figure data-label="$-0.0.0" data-group="$" class="invalid" data-invalid-syntax="figure" data-invalid-type="argument" data-invalid-message="Base index must be $-x.0 format"></figure>',
@@ -1,17 +1,18 @@
1
1
  import { Infinity, Set, Map } from 'spica/global';
2
2
  import { number as calculate, isFixed } from '../inline/extension/label';
3
- import { define } from 'typed-dom/dom';
4
3
  import { MultiMap } from 'spica/multimap';
5
4
  import { push } from 'spica/array';
5
+ import { define } from 'typed-dom/dom';
6
+ import { querySelectorAll } from 'typed-dom/query';
6
7
 
7
8
  export function* figure(
8
9
  target: ParentNode & Node,
9
10
  footnotes?: { readonly references: HTMLOListElement; },
10
11
  opts: { readonly id?: string; } = {},
11
12
  ): Generator<HTMLAnchorElement | undefined, undefined, undefined> {
12
- const refs = new MultiMap<string, HTMLAnchorElement>(push(push([],
13
- target.querySelectorAll('a.label:not(.disabled)[data-label]')),
14
- footnotes?.references.querySelectorAll('a.label:not(.disabled)') ?? [])
13
+ const refs = new MultiMap<string, HTMLAnchorElement>(push(
14
+ querySelectorAll(target, 'a.label:not(.disabled)[data-label]'),
15
+ footnotes && querySelectorAll(footnotes.references, 'a.label:not(.disabled)') || [])
15
16
  .map(el => [el.getAttribute('data-label')!, el]));
16
17
  const labels = new Set<string>();
17
18
  const numbers = new Map<string, string>();
@@ -19,10 +20,10 @@ export function* figure(
19
20
  let bases: readonly string[] = base.split('.');
20
21
  let index: readonly string[] = bases;
21
22
  // Bug: Firefox
22
- //for (let defs = target.querySelectorAll(':scope > figure[data-label], :scope > h1, :scope > h2'), i = 0, len = defs.length; i < len; ++i) {
23
+ //for (let defs = querySelectorAll(target, ':scope > figure[data-label], :scope > h1, :scope > h2'), len = defs.length, i = 0; i < len; ++i) {
23
24
  for (
24
- let defs = target.querySelectorAll('figure[data-label], h1, h2'),
25
- i = 0, len = defs.length; i < len; ++i) {
25
+ let defs = querySelectorAll(target, 'figure[data-label], h1, h2'),
26
+ len = defs.length, i = 0; i < len; ++i) {
26
27
  yield;
27
28
  const def = defs[i];
28
29
  if (def.parentNode !== target) continue;
@@ -141,7 +142,8 @@ export function* figure(
141
142
  }
142
143
  labels.add(label);
143
144
  opts.id !== '' && def.setAttribute('id', `label:${opts.id ? `${opts.id}:` : ''}${label}`);
144
- for (const ref of refs.take(label, Infinity)) {
145
+ for (let rs = refs.take(label, Infinity), i = 0; i < rs.length; ++i) {
146
+ const ref = rs[i];
145
147
  if (ref.getAttribute('data-invalid-message') === messages.reference) {
146
148
  define(ref, {
147
149
  class: void ref.classList.remove('invalid'),
@@ -151,8 +151,8 @@ describe('Unit: parser/processor/footnote', () => {
151
151
  assert.deepStrictEqual(
152
152
  [...target.children].map(el => el.outerHTML),
153
153
  [
154
- '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>',
155
- '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></aside>',
154
+ '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>',
155
+ '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></aside>',
156
156
  '<p><sup class="annotation" id="annotation:ref:1" title="a"><span hidden="">a</span><a href="#annotation:def:1">*1</a></sup></p>',
157
157
  ]);
158
158
  assert.deepStrictEqual(
@@ -1,9 +1,8 @@
1
1
  import { undefined, Infinity, Map, Node } from 'spica/global';
2
2
  import { text } from '../inline/extension/indexee';
3
- import { frag, html, define } from 'typed-dom/dom';
4
3
  import { MultiMap } from 'spica/multimap';
5
- import { duffEach, duffReduce } from 'spica/duff';
6
- import { push } from 'spica/array';
4
+ import { frag, html, define } from 'typed-dom/dom';
5
+ import { querySelectorAll } from 'typed-dom/query';
7
6
 
8
7
  export function* footnote(
9
8
  target: ParentNode & Node,
@@ -12,8 +11,11 @@ export function* footnote(
12
11
  bottom: Node | null = null,
13
12
  ): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
14
13
  // Bug: Firefox
15
- //target.querySelectorAll(`:scope > .annotations`).forEach(el => el.remove());
16
- duffEach(target.querySelectorAll(`.annotations`), el => el.parentNode === target && el.remove());
14
+ //querySelectorAll(target, `:scope > .annotations`).forEach(el => el.remove());
15
+ for (let es = querySelectorAll(target, `.annotations`), i = 0; i < es.length; ++i) {
16
+ const el = es[i];
17
+ el.parentNode === target && el.remove();
18
+ }
17
19
  yield* reference(target, footnotes?.references, opts, bottom);
18
20
  yield* annotation(target, footnotes?.annotations, opts, bottom);
19
21
  return;
@@ -40,16 +42,18 @@ function build(
40
42
  const buffer = new MultiMap<string, HTMLElement>();
41
43
  const titles = new Map<string, string>();
42
44
  // Bug: Firefox
43
- //const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
44
- const splitters = duffReduce(target.querySelectorAll(splitter ?? '_'), (acc, el) =>
45
- el.parentNode === target ? push(acc, [el]) : acc
46
- , [] as Element[]);
45
+ //const splitters = push([], querySelectorAll(target, `:scope > :is(${splitter ?? '_'})`));
46
+ const splitters: Element[] = [];
47
+ for (let es = querySelectorAll(target, splitter ?? '_'), i = 0; i < es.length; ++i) {
48
+ const el = es[i];
49
+ el.parentNode === target && splitters.push(el);
50
+ }
47
51
  let count = 0;
48
52
  let total = 0;
49
53
  let style: 'count' | 'abbr';
50
54
  for (
51
- let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`),
52
- i = 0, len = refs.length; i < len; ++i) {
55
+ let refs = querySelectorAll(target, `sup.${syntax}:not(.disabled)`),
56
+ len = refs.length, i = 0; i < len; ++i) {
53
57
  yield;
54
58
  const ref = refs[i];
55
59
  while (+splitters[0]?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
@@ -114,7 +118,8 @@ function build(
114
118
  if (title && !blank && def.childNodes.length === 1) {
115
119
  def.insertBefore(content.cloneNode(true), def.lastChild);
116
120
  assert(def.childNodes.length > 1);
117
- for (const ref of buffer.take(identifier, Infinity)) {
121
+ for (let refs = buffer.take(identifier, Infinity), i = 0; i < refs.length; ++i) {
122
+ const ref = refs[i];
118
123
  if (ref.getAttribute('data-invalid-type') !== 'content') continue;
119
124
  define(ref, {
120
125
  title,
@@ -3,8 +3,8 @@ import { RenderingOptions } from '../../';
3
3
  import { code } from './render/code';
4
4
  import { math } from './render/math';
5
5
  import { media } from './render/media';
6
- import { querySelectorAll } from 'typed-dom/query';
7
6
  import { reduce } from 'spica/memoize';
7
+ import { querySelectorAllWith } from 'typed-dom/query';
8
8
 
9
9
  const selector = 'img.media:not(.invalid):not([src])[data-src], a > :not(img).media:not(.invalid), pre.code:not(.invalid), .math:not(.invalid)';
10
10
 
@@ -14,8 +14,8 @@ const extend = reduce((opts: RenderingOptions): RenderingOptions =>
14
14
  export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
15
15
  opts = extend(opts);
16
16
  const base = location.href;
17
- for (const el of querySelectorAll<HTMLElement>(source, selector)) {
18
- render_(base, el, opts);
17
+ for (let es = querySelectorAllWith<HTMLElement>(source, selector), i = 0; i < es.length; ++i) {
18
+ render_(base, es[i], opts);
19
19
  }
20
20
  }
21
21
 
package/src/util/info.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Info } from '../..';
2
2
  import { scope } from './scope';
3
- import { duffReduce } from 'spica/duff';
4
- import { push } from 'spica/array';
3
+ import { querySelectorAll } from 'typed-dom/query';
5
4
 
6
5
  export function info(source: DocumentFragment | HTMLElement | ShadowRoot): Info {
7
6
  const match = scope(source, '.invalid');
@@ -19,8 +18,11 @@ export function info(source: DocumentFragment | HTMLElement | ShadowRoot): Info
19
18
  };
20
19
 
21
20
  function find<T extends HTMLElement>(selector: string): T[] {
22
- return duffReduce(source.querySelectorAll<T>(selector), (acc, el) =>
23
- match(el) ? push(acc, [el]) : acc
24
- , [] as T[]);
21
+ const acc: T[] = [];
22
+ for (let es = querySelectorAll<T>(source, selector), i = 0; i < es.length; ++i) {
23
+ const el = es[i];
24
+ match(el) && acc.push(el);
25
+ }
26
+ return acc;
25
27
  }
26
28
  }
package/src/util/quote.ts CHANGED
@@ -2,30 +2,31 @@ import { Element } from 'spica/global';
2
2
  import { exec } from '../combinator/data/parser';
3
3
  import { cite } from '../parser/block/reply/cite';
4
4
  import { define } from 'typed-dom/dom';
5
- import { duffEach } from 'spica/duff';
5
+ import { querySelectorAll } from 'typed-dom/query';
6
6
 
7
7
  export function quote(anchor: string, range: Range): string {
8
8
  if (exec(cite({ source: `>>${anchor}`, context: {} })) !== '') throw new Error(`Invalid anchor: ${anchor}`);
9
9
  fit(range);
10
10
  const node = trim(range.cloneContents());
11
11
  if (!node.firstChild) return '';
12
- duffEach(node.querySelectorAll('code[data-src], .math[data-src], .media[data-src], rt, rp'), el => {
12
+ for (let es = querySelectorAll(node, 'code[data-src], .math[data-src], .media[data-src], rt, rp'), i = 0; i < es.length; ++i) {
13
+ const el = es[i];
13
14
  switch (true) {
14
15
  case el.matches('code'):
15
16
  case el.matches('.math'):
16
17
  define(el, el.getAttribute('data-src')!);
17
- return;
18
+ continue;
18
19
  case el.matches('.media'):
19
20
  el.replaceWith(
20
21
  /[\s{}]/.test(el.getAttribute('data-src')!)
21
22
  ? `!{ ${el.getAttribute('data-src')} }`
22
23
  : `!{${el.getAttribute('data-src')}}`);
23
- return;
24
+ continue;
24
25
  case el.matches('rt, rp'):
25
26
  el.remove();
26
- return;
27
+ continue;
27
28
  }
28
- });
29
+ }
29
30
  if (range.startOffset === 0 &&
30
31
  range.startContainer.parentElement?.matches('.cite, .quote') &&
31
32
  (!range.startContainer.previousSibling || range.startContainer.previousSibling.nodeName === 'BR')) {
@@ -35,25 +36,26 @@ export function quote(anchor: string, range: Range): string {
35
36
  node.prepend(`>>${anchor}\n> `);
36
37
  anchor = '';
37
38
  }
38
- duffEach(node.querySelectorAll('br'), el => {
39
+ for (let es = querySelectorAll(node, 'br'), i = 0; i < es.length; ++i) {
40
+ const el = es[i];
39
41
  if (anchor && el.nextSibling instanceof Element && el.nextSibling.matches('.cite, .quote')) {
40
42
  el.replaceWith(`\n>${el.nextSibling.matches('.quote.invalid') ? ' ' : ''}`);
41
- return;
43
+ continue;
42
44
  }
43
45
  if (anchor && el.parentElement?.closest('.cite, .quote')) {
44
46
  el.replaceWith(`\n>${el.parentElement.closest('.quote.invalid') ? ' ' : ''}`);
45
- return;
47
+ continue;
46
48
  }
47
49
  if (anchor) {
48
50
  el.replaceWith(`\n>>${anchor}\n> `);
49
51
  anchor = '';
50
- return;
52
+ continue;
51
53
  }
52
54
  else {
53
55
  el.replaceWith(`\n> `);
54
- return;
56
+ continue;
55
57
  }
56
- });
58
+ }
57
59
  anchor && node.append(`\n>>${anchor}`);
58
60
  return node.textContent!;
59
61
  }
package/src/util/toc.ts CHANGED
@@ -1,22 +1,26 @@
1
1
  import { undefined } from 'spica/global';
2
- import { html } from 'typed-dom/dom';
3
- import { duffEach, duffReduce } from 'spica/duff';
4
2
  import { push } from 'spica/array';
3
+ import { html } from 'typed-dom/dom';
4
+ import { querySelectorAll } from 'typed-dom/query';
5
5
 
6
6
  // Bug: Firefox
7
7
  //const selector = 'h1 h2 h3 h4 h5 h6 aside.aside'.split(' ').map(s => `:scope > ${s}[id]`).join();
8
8
  const selector = ':is(h1, h2, h3, h4, h5, h6, aside.aside)[id]';
9
9
 
10
10
  export function toc(source: DocumentFragment | HTMLElement | ShadowRoot): HTMLUListElement {
11
- const hs = duffReduce(source.querySelectorAll(selector), (acc, el) => {
11
+ const hs: HTMLHeadingElement[] = [];
12
+ for (let es = querySelectorAll(source, selector), i = 0; i < es.length; ++i) {
13
+ const el = es[i];
12
14
  assert(el.parentNode === source);
13
15
  switch (el.tagName) {
14
16
  case 'ASIDE':
15
- return push(acc, [html(el.firstElementChild!.tagName.toLowerCase() as 'h1', { id: el.id, class: 'aside' }, el.firstElementChild!.cloneNode(true).childNodes)]);
17
+ hs.push(html(el.firstElementChild!.tagName.toLowerCase() as 'h1', { id: el.id, class: 'aside' }, el.firstElementChild!.cloneNode(true).childNodes));
18
+ continue;
16
19
  default:
17
- return push(acc, [el as HTMLHeadingElement]);
20
+ hs.push(el as HTMLHeadingElement);
21
+ continue;
18
22
  }
19
- }, [] as HTMLHeadingElement[]);
23
+ }
20
24
  return parse(cons(hs));
21
25
  }
22
26
 
@@ -58,7 +62,9 @@ function level(h: HTMLHeadingElement): number {
58
62
  }
59
63
 
60
64
  function unlink(h: HTMLHeadingElement): Iterable<Node> {
61
- duffEach(h.getElementsByTagName('a'), el =>
62
- void el.replaceWith(...el.childNodes));
65
+ for (let es = h.getElementsByTagName('a'), len = es.length, i = 0; i < len; ++i) {
66
+ const el = es[i];
67
+ el.replaceWith(...el.childNodes);
68
+ }
63
69
  return h.childNodes;
64
70
  }