securemark 0.221.0 → 0.224.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.
@@ -29,26 +29,34 @@ describe('Unit: parser/inline/media', () => {
29
29
  assert.deepStrictEqual(inspect(parser('![]{ }')), undefined);
30
30
  assert.deepStrictEqual(inspect(parser('![]]{/}')), undefined);
31
31
  assert.deepStrictEqual(inspect(parser('![]{{}')), undefined);
32
- assert.deepStrictEqual(inspect(parser('![]{{a}}')), undefined);
33
- assert.deepStrictEqual(inspect(parser('![]{a\nb}')), undefined);
34
- assert.deepStrictEqual(inspect(parser('![]{a\\\nb}')), undefined);
35
- assert.deepStrictEqual(inspect(parser('![]{ a}')), undefined);
36
- assert.deepStrictEqual(inspect(parser('![]{ a\n}')), undefined);
37
- assert.deepStrictEqual(inspect(parser('![ ]{#}')), undefined);
38
- assert.deepStrictEqual(inspect(parser('![ ]{#}')), undefined);
39
- assert.deepStrictEqual(inspect(parser('![\\ ]{#}')), undefined);
40
- assert.deepStrictEqual(inspect(parser('![	]{#}')), undefined);
32
+ assert.deepStrictEqual(inspect(parser('![]{{b}}')), undefined);
33
+ assert.deepStrictEqual(inspect(parser('![]{b\nc}')), undefined);
34
+ assert.deepStrictEqual(inspect(parser('![]{a\\\nc}')), undefined);
35
+ assert.deepStrictEqual(inspect(parser('![]{ b}')), undefined);
36
+ assert.deepStrictEqual(inspect(parser('![]{ b\n}')), undefined);
37
+ assert.deepStrictEqual(inspect(parser('![ ]{}')), undefined);
38
+ assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
39
+ assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
40
+ assert.deepStrictEqual(inspect(parser('![\n]{b}')), undefined);
41
+ assert.deepStrictEqual(inspect(parser('![\\ ]{b}')), undefined);
42
+ assert.deepStrictEqual(inspect(parser('![\\\n]{b}')), undefined);
43
+ assert.deepStrictEqual(inspect(parser('![	]{b}')), undefined);
44
+ assert.deepStrictEqual(inspect(parser('![[]{b}')), undefined);
45
+ assert.deepStrictEqual(inspect(parser('![]]{b}')), undefined);
41
46
  assert.deepStrictEqual(inspect(parser('![a]{}')), undefined);
42
- assert.deepStrictEqual(inspect(parser('![ a]{#}')), undefined);
43
- assert.deepStrictEqual(inspect(parser('![ a ]{#}')), undefined);
44
- assert.deepStrictEqual(inspect(parser('![\\ a ]{#}')), undefined);
45
- assert.deepStrictEqual(inspect(parser('![a\nb]{#}')), undefined);
46
- assert.deepStrictEqual(inspect(parser('![a\\\nb]{#}')), undefined);
47
+ assert.deepStrictEqual(inspect(parser('![\\ a ]{b}')), undefined);
48
+ assert.deepStrictEqual(inspect(parser('![ \\ a ]{b}')), undefined);
49
+ assert.deepStrictEqual(inspect(parser('![a\nb]{b}')), undefined);
50
+ assert.deepStrictEqual(inspect(parser('![a\\\nb]{b}')), undefined);
47
51
  assert.deepStrictEqual(inspect(parser('![]{ttp://host}')), [['<img class="media invalid" data-src="ttp://host" alt="">'], '']);
48
52
  assert.deepStrictEqual(inspect(parser('![]{tel:1234567890}')), [['<img class="media invalid" data-src="tel:1234567890" alt="">'], '']);
49
53
  //assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0%1]}')), [['<img class="media invalid" alt="">'], '']);
50
54
  //assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0/96]}')), [['<img class="media invalid" alt="">'], '']);
51
- assert.deepStrictEqual(inspect(parser(' ![]{a}')), undefined);
55
+ assert.deepStrictEqual(inspect(parser('![]{.}')), [['<img class="media invalid" data-src="." alt="">'], '']);
56
+ assert.deepStrictEqual(inspect(parser('![]{..}')), [['<img class="media invalid" data-src=".." alt="">'], '']);
57
+ assert.deepStrictEqual(inspect(parser('![]{../}')), [['<img class="media invalid" data-src="../" alt="">'], '']);
58
+ assert.deepStrictEqual(inspect(parser('![]{/../b}')), [['<img class="media invalid" data-src="/../b" alt="">'], '']);
59
+ assert.deepStrictEqual(inspect(parser(' ![]{b}')), undefined);
52
60
  assert.deepStrictEqual(inspect(parser('[]{/}')), undefined);
53
61
  });
54
62
 
@@ -61,8 +69,11 @@ describe('Unit: parser/inline/media', () => {
61
69
  assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
62
70
  assert.deepStrictEqual(inspect(parser('![]{\\ }')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
63
71
  assert.deepStrictEqual(inspect(parser('![]{\\b}')), [['<a href="\\b" target="_blank"><img class="media" data-src="\\b" alt=""></a>'], '']);
64
- assert.deepStrictEqual(inspect(parser('![]{./b}')), [['<a href="./b" target="_blank"><img class="media" data-src="./b" alt=""></a>'], '']);
72
+ assert.deepStrictEqual(inspect(parser('![]{?/../}')), [[`<a href="?/../" target="_blank"><img class="media" data-src="?/../" alt=""></a>`], '']);
73
+ assert.deepStrictEqual(inspect(parser('![]{#/../}')), [[`<a href="#/../" target="_blank"><img class="media" data-src="#/../" alt=""></a>`], '']);
65
74
  assert.deepStrictEqual(inspect(parser('![]{^/b}')), [[`<a href="/b" target="_blank"><img class="media" data-src="/b" alt=""></a>`], '']);
75
+ assert.deepStrictEqual(inspect(parser('![ a]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('![ a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
66
77
  assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
67
78
  assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
68
79
  assert.deepStrictEqual(inspect(parser('![a b]{c}')), [['<a href="c" target="_blank"><img class="media" data-src="c" alt="a b"></a>'], '']);
@@ -6,7 +6,6 @@ import { link, uri, option as linkoption, resolve } from './link';
6
6
  import { attributes } from './html';
7
7
  import { htmlentity } from './htmlentity';
8
8
  import { txt, str } from '../source';
9
- import { verifyStartTight } from '../util';
10
9
  import { html, define } from 'typed-dom';
11
10
  import { ReadonlyURL } from 'spica/url';
12
11
  import { unshift, push, join } from 'spica/array';
@@ -24,28 +23,29 @@ export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
24
23
  validate(['[', '{'], '}', '\n',
25
24
  guard(context => context.syntax?.inline?.media ?? true,
26
25
  tails([
27
- dup(surround(/^\[(?!\\?\s)/, some(union([htmlentity, bracket, txt]), ']', /^\\?\n/), ']', true)),
26
+ dup(surround(/^\[(?!\s*\\\s)/, some(union([htmlentity, bracket, txt]), ']', /^\\?\n/), ']', true)),
28
27
  dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
29
28
  ])))),
30
- ([as, bs]) => bs ? [[join(as)], bs] : [[''], as]),
31
- ([[text]]) => verifyStartTight([text || '-'])),
29
+ ([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
30
+ ([[text]]) => text === '' || text.trim() !== ''),
32
31
  ([[text], params], rest, context) => {
33
32
  const INSECURE_URI = params.shift()!;
34
33
  assert(INSECURE_URI === INSECURE_URI.trim());
35
34
  assert(!INSECURE_URI.match(/\s/));
36
35
  const url = new ReadonlyURL(
37
- resolve(INSECURE_URI, context.host || location, context.url || location),
36
+ resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
38
37
  context.host?.href || location.href);
39
- const cache = context.caches?.media;
40
- const cached = cache?.has(url.href);
41
- const el = cache && cached
42
- ? cache.get(url.href)!.cloneNode(true)
43
- : html('img', { class: 'media', 'data-src': url.source, alt: text.trimEnd() });
44
- if (!cached && !sanitize(url, el)) return [[el], rest];
45
- cached && el.hasAttribute('alt') && el.setAttribute('alt', text.trimEnd());
38
+ let cache: HTMLElement | undefined;
39
+ const el = undefined
40
+ || (cache = context.caches?.media?.get(url.href)?.cloneNode(true))
41
+ || html('img', { class: 'media', 'data-src': url.source, alt: text });
42
+ assert(!el.matches('.invalid'));
43
+ if (!cache && !sanitize(url, el)) return [[el], rest];
44
+ assert(!el.matches('.invalid'));
45
+ cache?.hasAttribute('alt') && cache?.setAttribute('alt', text);
46
46
  define(el, attributes('media', push([], el.classList), optspec, params));
47
47
  assert(el.matches('img') || !el.matches('.invalid'));
48
- if (context.syntax?.inline?.link === false || cached && el.tagName !== 'IMG') return [[el], rest];
48
+ if (context.syntax?.inline?.link === false || cache && cache.tagName !== 'IMG') return [[el], rest];
49
49
  return fmap(
50
50
  link as MediaParser,
51
51
  ([link]) => [define(link, { target: '_blank' }, [el])])
@@ -67,18 +67,29 @@ const option: MediaParser.ParameterParser.OptionParser = union([
67
67
 
68
68
  function sanitize(uri: ReadonlyURL, target: HTMLElement): boolean {
69
69
  assert(target.tagName === 'IMG');
70
+ assert(!target.matches('.invalid'));
71
+ if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
72
+ define(target, {
73
+ class: void target.classList.add('invalid'),
74
+ 'data-invalid-syntax': 'media',
75
+ 'data-invalid-type': 'argument',
76
+ 'data-invalid-description': 'Dot-segments cannot be used in media paths; use subresource paths instead.',
77
+ });
78
+ return false;
79
+ }
70
80
  switch (uri.protocol) {
71
81
  case 'http:':
72
82
  case 'https:':
73
83
  assert(uri.host);
74
- return true;
84
+ break;
85
+ default:
86
+ define(target, {
87
+ class: void target.classList.add('invalid'),
88
+ 'data-invalid-syntax': 'media',
89
+ 'data-invalid-type': 'argument',
90
+ 'data-invalid-description': 'Invalid protocol.',
91
+ });
92
+ return false;
75
93
  }
76
- assert(!target.classList.contains('invalid'));
77
- define(target, {
78
- class: void target.classList.add('invalid'),
79
- 'data-invalid-syntax': 'media',
80
- 'data-invalid-type': 'argument',
81
- 'data-invalid-description': 'Invalid protocol.',
82
- });
83
- return false;
94
+ return true;
84
95
  }
@@ -14,8 +14,6 @@ describe('Unit: parser/inline/reference', () => {
14
14
  assert.deepStrictEqual(inspect(parser('[[]]')), undefined);
15
15
  assert.deepStrictEqual(inspect(parser('[[]]]')), undefined);
16
16
  assert.deepStrictEqual(inspect(parser('[[ ]]')), undefined);
17
- assert.deepStrictEqual(inspect(parser('[[ a]]')), undefined);
18
- assert.deepStrictEqual(inspect(parser('[[ a ]]')), undefined);
19
17
  assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
20
18
  assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
21
19
  assert.deepStrictEqual(inspect(parser('[[\\ a]]')), undefined);
@@ -34,6 +32,8 @@ describe('Unit: parser/inline/reference', () => {
34
32
  });
35
33
 
36
34
  it('basic', () => {
35
+ assert.deepStrictEqual(inspect(parser('[[ a]]')), [['<sup class="reference">a</sup>'], '']);
36
+ assert.deepStrictEqual(inspect(parser('[[ a ]]')), [['<sup class="reference">a</sup>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser('[[a]]')), [['<sup class="reference">a</sup>'], '']);
38
38
  assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
@@ -3,13 +3,13 @@ import { ReferenceParser } from '../inline';
3
3
  import { union, subsequence, some, validate, verify, focus, guard, context, creator, surround, lazy, fmap } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
- import { startTight, isStartTight, trimEnd, stringify } from '../util';
6
+ import { startLoose, isStartLoose, trimNode, stringify } from '../util';
7
7
  import { html, defrag } from 'typed-dom';
8
8
 
9
9
  export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
10
10
  '[[',
11
11
  guard(context => context.syntax?.inline?.reference ?? true,
12
- startTight(
12
+ startLoose(
13
13
  context({ syntax: { inline: {
14
14
  annotation: false,
15
15
  reference: false,
@@ -24,15 +24,15 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
24
24
  abbr,
25
25
  focus('^', c => [['', c], '']),
26
26
  some(inline, ']', /^\\?\n/),
27
- ])))),
27
+ ])), ']]')),
28
28
  ']]'),
29
- ns => [html('sup', attributes(ns), trimEnd(defrag(ns)))]))));
29
+ ns => [html('sup', attributes(ns), trimNode(defrag(ns)))]))));
30
30
 
31
31
  const abbr: ReferenceParser.AbbrParser = creator(fmap(verify(surround(
32
32
  '^',
33
33
  union([str(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]),
34
- /^\|?(?=]])|^\|[^\S\n]+/),
35
- (_, rest, context) => isStartTight(rest, context)),
34
+ /^\|?(?=]])|^\|[^\S\n]/),
35
+ (_, rest, context) => isStartLoose(rest, context)),
36
36
  ([source]) => [html('abbr', source)]));
37
37
 
38
38
  function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
@@ -4,7 +4,7 @@ import { eval, exec } from '../../combinator/data/parser';
4
4
  import { sequence, validate, verify, focus, creator, surround, lazy, bind } from '../../combinator';
5
5
  import { htmlentity } from './htmlentity';
6
6
  import { text as txt } from '../source';
7
- import { verifyStartTight } from '../util';
7
+ import { isStartTightNodes } from '../util';
8
8
  import { html, defrag } from 'typed-dom';
9
9
  import { unshift, push, join } from 'spica/array';
10
10
 
@@ -14,7 +14,7 @@ export const ruby: RubyParser = lazy(() => creator(bind(verify(
14
14
  surround('[', focus(/^(?:\\[^\n]|[^\[\]\n])+(?=]\()/, text), ']'),
15
15
  surround('(', focus(/^(?:\\[^\n]|[^\(\)\n])+(?=\))/, text), ')'),
16
16
  ])),
17
- ([texts]) => verifyStartTight(texts)),
17
+ ([texts]) => isStartTightNodes(texts)),
18
18
  ([texts, rubies], rest) => {
19
19
  const tail = typeof texts[texts.length - 1] === 'object'
20
20
  ? [texts.pop()!]
@@ -3,7 +3,7 @@ import { union, some, creator, surround, close, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { emphasis } from './emphasis';
5
5
  import { str } from '../source';
6
- import { startTight, verifyEndTight, trimEndBR } from '../util';
6
+ import { startTight, isEndTightNodes, trimEndBR } from '../util';
7
7
  import { html, defrag } from 'typed-dom';
8
8
  import { unshift } from 'spica/array';
9
9
 
@@ -12,7 +12,7 @@ export const strong: StrongParser = lazy(() => creator(surround(close(
12
12
  startTight(some(union([emphasis, some(inline, '*'), str('*')]), '**')),
13
13
  str('**'), false,
14
14
  ([as, bs, cs], rest) =>
15
- verifyEndTight(bs)
15
+ isEndTightNodes(bs)
16
16
  ? [[html('strong', defrag(trimEndBR(bs)))], rest]
17
17
  : [unshift(as, bs), cs[0] + rest],
18
18
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -70,6 +70,19 @@ function hasVisible(
70
70
  return false;
71
71
  }
72
72
 
73
+ export function startLoose<P extends Parser<HTMLElement | string>>(parser: P, except?: string): P;
74
+ export function startLoose<T extends HTMLElement | string>(parser: Parser<T>, except?: string): Parser<T> {
75
+ return (source, context) =>
76
+ isStartLoose(source, context, except)
77
+ ? parser(source, context)
78
+ : undefined;
79
+ }
80
+ export function isStartLoose(source: string, context: MarkdownParser.Context, except?: string): boolean {
81
+ source &&= source.replace(/^[^\S\n]+/, '');
82
+ if (source === '') return true;
83
+ return source.slice(0, except?.length ?? 0) !== except
84
+ && isStartTight(source, context);
85
+ }
73
86
  export function startTight<P extends Parser<unknown>>(parser: P): P;
74
87
  export function startTight<T>(parser: Parser<T>): Parser<T> {
75
88
  return (source, context) =>
@@ -77,8 +90,7 @@ export function startTight<T>(parser: Parser<T>): Parser<T> {
77
90
  ? parser(source, context)
78
91
  : undefined;
79
92
  }
80
-
81
- export function isStartTight(source: string, context: MarkdownParser.Context): boolean {
93
+ function isStartTight(source: string, context: MarkdownParser.Context): boolean {
82
94
  if (source === '') return true;
83
95
  switch (source[0]) {
84
96
  case ' ':
@@ -117,11 +129,11 @@ export function isStartTight(source: string, context: MarkdownParser.Context): b
117
129
  return source[0].trimStart() !== '';
118
130
  }
119
131
  }
120
- export function verifyStartTight(nodes: readonly (HTMLElement | string)[]): boolean {
132
+ export function isStartTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
121
133
  if (nodes.length === 0) return true;
122
- return isVisible(nodes[0]);
134
+ return isVisible(nodes[0], 0);
123
135
  }
124
- export function verifyEndTight(nodes: readonly (HTMLElement | string)[]): boolean {
136
+ export function isEndTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
125
137
  if (nodes.length === 0) return true;
126
138
  const last = nodes.length - 1;
127
139
  return typeof nodes[last] === 'string' && (nodes[last] as string).length > 1
@@ -130,12 +142,13 @@ export function verifyEndTight(nodes: readonly (HTMLElement | string)[]): boolea
130
142
  : isVisible(nodes[last], -1) || last === 0 ||
131
143
  isVisible(nodes[last - 1], -1);
132
144
  }
133
- function isVisible(node: HTMLElement | string, position = 0): boolean {
145
+ function isVisible(node: HTMLElement | string, position?: number): boolean {
134
146
  if (!node) return false;
135
147
  switch (typeof node) {
136
148
  case 'string':
137
- assert(node.length + position >= 0);
138
- const char = node[position >= 0 ? position : node.length + position];
149
+ const char = position === undefined
150
+ ? node
151
+ : node[position >= 0 ? position : node.length + position];
139
152
  assert(char);
140
153
  switch (char) {
141
154
  case ' ':
@@ -160,8 +173,34 @@ function isVisible(node: HTMLElement | string, position = 0): boolean {
160
173
  }
161
174
  }
162
175
 
163
- export function trimEnd(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
164
- assert(verifyStartTight(nodes));
176
+ export function trimNode(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
177
+ return trimNodeStart(trimNodeEnd(nodes));
178
+ }
179
+ function trimNodeStart(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
180
+ const skip = nodes.length > 0 &&
181
+ typeof nodes[nodes.length - 1] === 'object' &&
182
+ nodes[nodes.length - 1]['className'] === 'indexer'
183
+ ? [nodes.pop()!]
184
+ : [];
185
+ for (
186
+ let first = nodes[0];
187
+ nodes.length > 0 &&
188
+ !isVisible(first, 0) &&
189
+ !(typeof first === 'object' && first.className === 'comment');
190
+ ) {
191
+ assert(nodes.length > 0);
192
+ if (typeof first === 'string') {
193
+ const pos = first.length - first.trimStart().length;
194
+ if (pos > 0) {
195
+ nodes[0] = first.slice(pos);
196
+ break;
197
+ }
198
+ }
199
+ nodes.pop();
200
+ }
201
+ return push(nodes, skip);
202
+ }
203
+ export function trimNodeEnd(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
165
204
  const skip = nodes.length > 0 &&
166
205
  typeof nodes[nodes.length - 1] === 'object' &&
167
206
  nodes[nodes.length - 1]['className'] === 'indexer'
@@ -13,7 +13,7 @@ export function math(target: HTMLElement, cache?: Collection<string, HTMLElement
13
13
 
14
14
  async function queue(target: HTMLElement, callback = () => undefined): Promise<void> {
15
15
  // @ts-ignore
16
- MathJax.typesetPromise || await MathJax.startup.promise;
16
+ !MathJax.typesetPromise && await MathJax.startup.promise;
17
17
  // @ts-ignore
18
18
  MathJax.typesetPromise([target]).then(callback);
19
19
  }
@@ -12,7 +12,6 @@ const extend = reduce((opts: RenderingOptions): RenderingOptions =>
12
12
 
13
13
  export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
14
14
  opts = extend(opts);
15
- if (source.classList.contains('invalid')) return;
16
15
  const base = location.href;
17
16
  if (source.matches(selector)) return void render_(base, source, opts);
18
17
  for (
@@ -23,7 +22,7 @@ export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
23
22
  }
24
23
 
25
24
  function render_(base: string, source: HTMLElement, opts: RenderingOptions): void {
26
- assert(!source.matches('.invalid'));
25
+ if (source.classList.contains('invalid')) return;
27
26
  try {
28
27
  switch (true) {
29
28
  case !!opts.code
package/tsconfig.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2019",
4
+ "lib": [
5
+ "ES2019",
6
+ "ES2021.Promise",
7
+ "DOM",
8
+ "DOM.Iterable"
9
+ ],
4
10
  "module": "commonjs",
5
11
  "moduleResolution": "node",
6
12
  "esModuleInterop": true,