securemark 0.267.0 → 0.268.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.
@@ -1,5 +1,4 @@
1
1
  import { text } from '../inline/extension/indexee';
2
- import { MultiQueue } from 'spica/queue';
3
2
  import { frag, html, define } from 'typed-dom/dom';
4
3
 
5
4
  export function* footnote(
@@ -24,7 +23,7 @@ export const reference = build('reference', (n, abbr) => `[${abbr || n}]`);
24
23
  function build(
25
24
  syntax: 'annotation' | 'reference',
26
25
  marker: (index: number, abbr: string | undefined) => string,
27
- splitter?: string,
26
+ splitter: string = '_',
28
27
  ) {
29
28
  assert(syntax.match(/^[a-z]+$/));
30
29
  // Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
@@ -36,21 +35,31 @@ function build(
36
35
  bottom: Node | null = null,
37
36
  ): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
38
37
  const defs = new Map<string, HTMLLIElement>();
39
- const buffer = new MultiQueue<string, HTMLElement>();
40
- const titles = new Map<string, string>();
41
38
  const splitters: Element[] = [];
42
- for (let es = target.querySelectorAll(splitter ?? '_'),
39
+ for (let es = target.querySelectorAll(splitter),
43
40
  len = es.length, i = 0; i < len; ++i) {
41
+ if (i % 100 === 0) yield;
44
42
  const el = es[i];
45
43
  el.parentNode === target && splitters.push(el);
46
44
  }
45
+ const refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`);
46
+ const titles = new Map<string, string>();
47
+ const contents = new Map<string, DocumentFragment>();
48
+ for (let len = refs.length, i = 0; i < len; ++i) {
49
+ if (i % 10 === 9) yield;
50
+ const ref = refs[i];
51
+ const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild!.innerHTML}`;
52
+ if (titles.has(identifier)) continue;
53
+ const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
54
+ const title = text(content).trim();
55
+ if (!title) continue;
56
+ titles.set(identifier, title);
57
+ contents.set(identifier, content);
58
+ }
47
59
  let count = 0;
48
60
  let total = 0;
49
61
  let style: 'count' | 'abbr';
50
- for (
51
- let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`),
52
- len = refs.length, i = 0; i < len; ++i) {
53
- yield;
62
+ for (let len = refs.length, i = 0; i < len; ++i) {
54
63
  const ref = refs[i];
55
64
  while (splitters.length > 0
56
65
  && splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
@@ -65,7 +74,6 @@ function build(
65
74
  }
66
75
  const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild!.innerHTML}`;
67
76
  const abbr = ref.getAttribute('data-abbr') || undefined;
68
- const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
69
77
  style ??= abbr ? 'abbr' : 'count';
70
78
  if (style === 'count' ? abbr : !abbr) {
71
79
  define(ref, {
@@ -89,14 +97,10 @@ function build(
89
97
  else {
90
98
  ref.lastChild?.remove();
91
99
  }
92
- const title = titles.get(identifier) || text(content).trim() || undefined;
100
+ const title = titles.get(identifier);
93
101
  assert(title !== '');
94
102
  assert(syntax !== 'annotation' || title);
95
- title
96
- ? !titles.has(identifier) && titles.set(identifier, title)
97
- : buffer.set(identifier, ref);
98
- assert(syntax !== 'annotation' || !buffer.has(identifier));
99
- const blank = !!abbr && !content.firstChild;
103
+ const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
100
104
  const refIndex = ++count;
101
105
  const refId = opts.id !== ''
102
106
  ? `${syntax}:${opts.id ?? ''}:ref:${refIndex}`
@@ -108,24 +112,9 @@ function build(
108
112
  id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${total + defs.size + 1}` : undefined,
109
113
  'data-marker': !footnote ? marker(total + defs.size + 1, abbr) : undefined,
110
114
  },
111
- [content.cloneNode(true), html('sup')]))
115
+ [contents.get(identifier) ?? frag(), html('sup')]))
112
116
  .get(identifier)!;
113
117
  assert(def.lastChild);
114
- if (title && !blank && def.childNodes.length === 1) {
115
- def.insertBefore(content.cloneNode(true), def.lastChild);
116
- assert(def.childNodes.length > 1);
117
- for (let refs = buffer.take(identifier, Infinity), i = 0; i < refs.length; ++i) {
118
- const ref = refs[i];
119
- if (ref.getAttribute('data-invalid-type') !== 'content') continue;
120
- define(ref, {
121
- title,
122
- class: void ref.classList.remove('invalid'),
123
- 'data-invalid-syntax': null,
124
- 'data-invalid-type': null,
125
- 'data-invalid-message': null,
126
- });
127
- }
128
- }
129
118
  const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || total + defs.size;
130
119
  const defId = def.id || undefined;
131
120
  define(ref, {
@@ -145,9 +134,7 @@ function build(
145
134
  html('a',
146
135
  {
147
136
  href: refId && `#${refId}`,
148
- title: abbr && !blank
149
- ? title
150
- : undefined,
137
+ title: abbr && text(content).trim() || undefined,
151
138
  },
152
139
  `^${refIndex}`));
153
140
  }
@@ -1,6 +1,6 @@
1
1
  import { AnyLineParser, EmptyLineParser, ContentLineParser } from '../source';
2
- import { line, isEmpty } from '../../combinator';
2
+ import { line, isBlank } from '../../combinator';
3
3
 
4
4
  export const anyline: AnyLineParser = line(() => [[], '']);
5
- export const emptyline: EmptyLineParser = line(i => isEmpty(i.source) ? [[], ''] : undefined);
6
- export const contentline: ContentLineParser = line(i => !isEmpty(i.source) ? [[], ''] : undefined);
5
+ export const emptyline: EmptyLineParser = line(i => isBlank(i.source) ? [[], ''] : undefined);
6
+ export const contentline: ContentLineParser = line(i => !isBlank(i.source) ? [[], ''] : undefined);
@@ -31,7 +31,7 @@ export function stropt(pattern: string | RegExp): Parser<string, Context<StrPars
31
31
  if (source === '') return;
32
32
  return source.slice(0, pattern.length) === pattern
33
33
  ? [[pattern], source.slice(pattern.length)]
34
- : undefined;
34
+ : [[''], source];
35
35
  })
36
36
  : creation(1, false, ({ source }) => {
37
37
  if (source === '') return;
@@ -1,3 +1,13 @@
1
+ import { Parser } from '../combinator/data/parser';
2
+ import { convert } from '../combinator';
3
+
4
+ export function format<P extends Parser<HTMLElement | string>>(parser: P): P;
5
+ export function format<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
6
+ return convert(
7
+ source => source.replace(/(?<=^!?)https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=[^\S\n]*(?:$|\n))/gm, '{ $& }'),
8
+ parser);
9
+ }
10
+
1
11
  export function stringify(nodes: readonly (HTMLElement | string)[]): string {
2
12
  let acc = '';
3
13
  for (let i = 0; i < nodes.length; ++i) {
@@ -4,6 +4,7 @@ import { union, some, verify, convert, fmap } from '../combinator';
4
4
  import { unsafehtmlentity } from './inline/htmlentity';
5
5
  import { linebreak, unescsource } from './source';
6
6
  import { State } from './context';
7
+ import { format } from './util';
7
8
  import { invisibleHTMLEntityNames } from './api/normalize';
8
9
  import { reduce } from 'spica/memoize';
9
10
  import { push } from 'spica/array';
@@ -16,7 +17,7 @@ export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Pa
16
17
  return union([
17
18
  convert(
18
19
  source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')),
19
- verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
20
+ verify(format(parser), (ns, rest, context) => !rest && hasVisible(ns, context))),
20
21
  some(union([linebreak, unescsource])),
21
22
  ]);
22
23
  }
package/src/util/quote.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { exec } from '../combinator/data/parser';
2
2
  import { cite } from '../parser/block/reply/cite';
3
- import { define } from 'typed-dom/dom';
3
+ //import { url } from '../parser/inline/autolink/url';
4
4
 
5
5
  export function quote(anchor: string, range: Range): string {
6
6
  if (exec(cite({ source: `>>${anchor}`, context: {} })) !== '') throw new Error(`Invalid anchor: ${anchor}`);
@@ -13,8 +13,15 @@ export function quote(anchor: string, range: Range): string {
13
13
  switch (true) {
14
14
  case el.matches('code'):
15
15
  case el.matches('.math'):
16
- define(el, el.getAttribute('data-src')!);
16
+ el.replaceWith(el.getAttribute('data-src')!);
17
17
  continue;
18
+ //case el.matches('.url'):
19
+ // if (exec(url({ source: el.getAttribute('href')!, context: {} })) === '') continue;
20
+ // el.replaceWith(
21
+ // /[\s{}]/.test(el.getAttribute('href')!)
22
+ // ? `{ ${el.getAttribute('href')} }`
23
+ // : `{${el.getAttribute('href')}}`);
24
+ // continue;
18
25
  case el.matches('.media'):
19
26
  el.replaceWith(
20
27
  /[\s{}]/.test(el.getAttribute('data-src')!)