securemark 0.274.1 → 0.274.3

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,9 +1,13 @@
1
1
  import { identity, text } from '../inline/extension/indexee';
2
+ import { markInvalid, unmarkInvalid } from '../util';
2
3
  import { frag, html, define } from 'typed-dom/dom';
3
4
 
4
5
  export function* note(
5
6
  target: ParentNode & Node,
6
- notes?: { readonly annotations?: HTMLOListElement; readonly references: HTMLOListElement; },
7
+ notes?: {
8
+ readonly annotations?: HTMLOListElement;
9
+ readonly references: HTMLOListElement;
10
+ },
7
11
  opts: { readonly id?: string; } = {},
8
12
  bottom: Node | null = null,
9
13
  ): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
@@ -35,40 +39,46 @@ function build(
35
39
  bottom: Node | null = null,
36
40
  ): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
37
41
  const defs = new Map<string, HTMLLIElement>();
38
- const splitters: Element[] = [];
39
- for (let es = target.querySelectorAll(splitter || '_'),
40
- len = es.length, i = 0; i < len; ++i) {
41
- if (i % 100 === 0) yield;
42
- const el = es[i];
43
- el.parentNode === target && splitters.push(el);
44
- }
45
42
  const refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`);
46
43
  const titles = new Map<string, string>();
47
44
  const defIndexes = new Map<HTMLLIElement, number>();
48
45
  const refSubindexes = new Map<string, number>();
49
- const defSubindexes = new Map<string, number>();
50
- let refIndex = 0;
46
+ const defSubindexes = splitter && refs.length > 0 ? new Map<string, number>() : undefined;
47
+ const splitters = splitter && refs.length > 0 ? target.querySelectorAll(splitter) : [];
48
+ let iSplitters = 0;
51
49
  let total = 0;
52
- let style: 'count' | 'abbr';
50
+ let format: 'number' | 'abbr';
51
+ let refIndex = 0;
53
52
  for (let len = refs.length, i = 0; i < len; ++i) {
54
53
  const ref = refs[i];
55
- if (ref.closest('[hidden]')) {
54
+ if (ref.closest('sup > [hidden]')) {
56
55
  yield;
57
56
  continue;
58
57
  }
59
- while (splitters.length > 0
60
- && splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
58
+ if (splitter) for (
59
+ let el: Element;
60
+ (el = splitters[iSplitters])?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING;
61
+ ++iSplitters) {
62
+ if (el.parentNode !== target) continue;
61
63
  if (defs.size > 0) {
62
64
  total += defs.size;
63
- yield* proc(defs, target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0]));
65
+ yield* proc(defs, target.insertBefore(html('ol', { class: `${syntax}s` }), el));
66
+ assert(defs.size === 0);
64
67
  }
65
- else if (splitters.length % 100 === 0) {
68
+ else if (~iSplitters % 128 === 0) {
66
69
  yield;
67
70
  }
68
- splitters.shift();
69
71
  }
70
72
  const abbr = ref.getAttribute('data-abbr') || undefined;
71
- const identifier = abbr || identity(undefined, text(ref.firstElementChild!), 'mark')?.slice(6) || '';
73
+ const identifier = identity(
74
+ undefined,
75
+ abbr
76
+ ? abbr.match(/^(?:\S+ )+?(?:(?:January|February|March|April|May|June|August|September|October|November|December) \d{1,2}(?:-\d{0,2})?, \d{1,4}(?:-\d{0,4})?[a-z]?|n\.d\.)(?=,|$)/)?.[0] ??
77
+ abbr.match(/^[^,\s]+(?:,? [^,\s]+)*?(?: \d{1,4}(?:-\d{0,4})?[a-z]?(?=,|$)|(?=,(?: [a-z]+\.?)? [0-9]))/)?.[0] ??
78
+ abbr
79
+ : text(ref.firstElementChild!),
80
+ 'mark')
81
+ ?.slice(6) || '';
72
82
  const refSubindex = refSubindexes.get(identifier)! + 1 || 1;
73
83
  refSubindexes.set(identifier, refSubindex);
74
84
  const refId = opts.id !== ''
@@ -77,65 +87,55 @@ function build(
77
87
  const initial = splitter
78
88
  ? !defs.has(identifier)
79
89
  : refSubindex === 1;
80
- const defSubindex = defSubindexes.get(identifier)! + 1 || 1;
81
- defSubindexes.set(identifier, defSubindex);
90
+ const defSubindex = defSubindexes?.get(identifier)! + +initial || 1;
91
+ initial && defSubindexes?.set(identifier, defSubindex);
92
+ const defId = opts.id !== ''
93
+ ? `${syntax}:${opts.id ?? ''}:def:${identifier}${splitter && `:${defSubindex}`}`
94
+ : undefined;
82
95
  const def = initial
83
96
  ? html('li',
84
97
  {
85
- id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${identifier}:${defSubindex}` : undefined,
86
- 'data-marker': !note ? marker(total + defs.size + 1, abbr) : undefined,
98
+ id: defId,
99
+ 'data-marker': note ? undefined : marker(total + defs.size + 1, abbr),
87
100
  },
88
101
  [define(ref.firstElementChild!.cloneNode(true), { hidden: null }), html('sup')])
89
102
  : defs.get(identifier)!;
90
103
  initial && defs.set(identifier, def);
91
- assert(def.lastChild);
104
+ assert(def.lastElementChild?.matches('sup'));
92
105
  const defIndex = initial
93
106
  ? total + defs.size
94
107
  : defIndexes.get(def)!;
95
108
  initial && defIndexes.set(def, defIndex);
96
- const defId = def.id || undefined;
97
109
  const title = initial
98
110
  ? text(ref.firstElementChild!)
99
111
  : titles.get(identifier)!;
100
112
  initial && titles.set(identifier, title);
101
113
  assert(syntax !== 'annotation' || title);
102
- style ??= abbr ? 'abbr' : 'count';
103
- if (style === 'count' ? abbr : !abbr) {
104
- define(ref, {
105
- class: void ref.classList.add('invalid'),
106
- 'data-invalid-syntax': syntax,
107
- 'data-invalid-type': 'style',
108
- 'data-invalid-message': `${syntax[0].toUpperCase() + syntax.slice(1)} style must be consistent`,
109
- });
110
- }
111
- else if (ref.getAttribute('data-invalid-type') === 'style') {
112
- define(ref, {
113
- class: void ref.classList.remove('invalid'),
114
- 'data-invalid-syntax': null,
115
- 'data-invalid-type': null,
116
- 'data-invalid-message': null,
117
- });
118
- }
119
- if (!ref.firstElementChild!.hasAttribute('hidden')) {
120
- ref.firstElementChild!.setAttribute('hidden', '');
121
- }
122
- else {
123
- ref.lastChild?.remove();
124
- }
114
+ ref.firstElementChild!.hasAttribute('hidden')
115
+ ? ref.lastElementChild!.remove()
116
+ : ref.firstElementChild!.setAttribute('hidden', '');
125
117
  define(ref, {
126
118
  id: refId,
127
119
  class: opts.id !== '' ? undefined : void ref.classList.add('disabled'),
128
120
  title,
129
- ...!title && {
130
- class: void ref.classList.add('invalid'),
131
- 'data-invalid-syntax': syntax,
132
- 'data-invalid-type': 'content',
133
- 'data-invalid-message': 'Missing the content',
134
- },
135
121
  });
122
+ switch (ref.getAttribute('data-invalid-syntax')) {
123
+ case 'format':
124
+ case 'content':
125
+ unmarkInvalid(ref);
126
+ }
127
+ format ??= abbr ? 'abbr' : 'number';
128
+ if (!ref.classList.contains('invalid')) switch (true) {
129
+ case format === 'number' ? !!abbr : !abbr:
130
+ markInvalid(ref, syntax, 'format', 'Notation format must be consistent with numbers or abbreviations');
131
+ break;
132
+ case !title:
133
+ markInvalid(ref, syntax, 'content', 'Missing the content');
134
+ break;
135
+ }
136
136
  yield ref.appendChild(html('a', { href: refId && defId && `#${defId}` }, marker(defIndex, abbr)));
137
137
  assert(ref.title || ref.matches('.invalid'));
138
- def.lastChild!.appendChild(
138
+ def.lastElementChild!.appendChild(
139
139
  html('a',
140
140
  {
141
141
  href: refId && `#${refId}`,
@@ -143,8 +143,8 @@ function build(
143
143
  },
144
144
  `^${++refIndex}`));
145
145
  }
146
- if (defs.size > 0 || note) {
147
- yield* proc(defs, note ?? target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0] ?? bottom));
146
+ if (note || defs.size > 0) {
147
+ yield* proc(defs, note ?? target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[iSplitters] ?? bottom));
148
148
  }
149
149
  return;
150
150
  }
@@ -1,3 +1,29 @@
1
+ import { define } from 'typed-dom/dom';
2
+
3
+ export function markInvalid<T extends Element>(
4
+ el: T,
5
+ syntax: string,
6
+ type: string,
7
+ message: string,
8
+ ): T {
9
+ assert(!message.endsWith('.'));
10
+ return define(el, {
11
+ class: void el.classList.add('invalid'),
12
+ 'data-invalid-syntax': syntax,
13
+ 'data-invalid-type': type,
14
+ 'data-invalid-message': message,
15
+ });
16
+ }
17
+
18
+ export function unmarkInvalid<T extends Element>(el: T): T {
19
+ return define(el, {
20
+ class: void el.classList.remove('invalid'),
21
+ 'data-invalid-syntax': null,
22
+ 'data-invalid-type': null,
23
+ 'data-invalid-message': null,
24
+ });
25
+ }
26
+
1
27
  export function stringify(nodes: readonly (HTMLElement | string)[]): string {
2
28
  let acc = '';
3
29
  for (let i = 0; i < nodes.length; ++i) {