securemark 0.235.0 → 0.235.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/securemark.js +197 -177
  3. package/markdown.d.ts +5 -2
  4. package/package-lock.json +36 -60
  5. package/package.json +3 -3
  6. package/src/combinator/control/manipulation/context.test.ts +4 -4
  7. package/src/combinator/control/manipulation/resource.ts +6 -3
  8. package/src/combinator/control/manipulation/surround.ts +3 -4
  9. package/src/combinator/data/parser/inits.ts +1 -1
  10. package/src/combinator/data/parser/sequence.ts +1 -1
  11. package/src/combinator/data/parser/some.ts +23 -25
  12. package/src/combinator/data/parser.ts +33 -10
  13. package/src/parser/api/bind.test.ts +3 -3
  14. package/src/parser/api/parse.test.ts +12 -5
  15. package/src/parser/block/blockquote.test.ts +1 -1
  16. package/src/parser/block/extension/aside.test.ts +1 -1
  17. package/src/parser/block/extension/example.test.ts +2 -2
  18. package/src/parser/block/extension/fig.test.ts +20 -20
  19. package/src/parser/block/extension/figure.test.ts +31 -28
  20. package/src/parser/block/extension/figure.ts +5 -3
  21. package/src/parser/block/extension/table.ts +6 -6
  22. package/src/parser/block/paragraph.test.ts +1 -1
  23. package/src/parser/block.ts +1 -2
  24. package/src/parser/inline/annotation.ts +3 -3
  25. package/src/parser/inline/bracket.test.ts +10 -10
  26. package/src/parser/inline/bracket.ts +5 -8
  27. package/src/parser/inline/deletion.test.ts +4 -1
  28. package/src/parser/inline/deletion.ts +7 -4
  29. package/src/parser/inline/emphasis.ts +3 -6
  30. package/src/parser/inline/emstrong.ts +7 -8
  31. package/src/parser/inline/html.test.ts +25 -17
  32. package/src/parser/inline/html.ts +39 -15
  33. package/src/parser/inline/htmlentity.test.ts +1 -1
  34. package/src/parser/inline/htmlentity.ts +17 -10
  35. package/src/parser/inline/insertion.test.ts +4 -1
  36. package/src/parser/inline/insertion.ts +7 -4
  37. package/src/parser/inline/link.test.ts +3 -0
  38. package/src/parser/inline/link.ts +6 -7
  39. package/src/parser/inline/mark.ts +3 -6
  40. package/src/parser/inline/media.test.ts +3 -0
  41. package/src/parser/inline/media.ts +1 -1
  42. package/src/parser/inline/reference.ts +6 -6
  43. package/src/parser/inline/ruby.ts +1 -1
  44. package/src/parser/inline/strong.test.ts +1 -1
  45. package/src/parser/inline/strong.ts +3 -6
  46. package/src/parser/inline.test.ts +2 -3
  47. package/src/parser/processor/figure.test.ts +28 -28
  48. package/src/parser/processor/figure.ts +1 -1
  49. package/src/parser/util.ts +43 -39
package/markdown.d.ts CHANGED
@@ -852,7 +852,6 @@ export namespace MarkdownParser {
852
852
  SourceParser.StrParser,
853
853
  SourceParser.StrParser,
854
854
  SourceParser.StrParser,
855
- SourceParser.StrParser,
856
855
  ]> {
857
856
  }
858
857
  }
@@ -927,6 +926,7 @@ export namespace MarkdownParser {
927
926
  HTMLParser.OpenTagParser,
928
927
  HTMLParser.TagParser,
929
928
  HTMLParser.TagParser,
929
+ HTMLParser.TagParser,
930
930
  ]> {
931
931
  }
932
932
  export namespace HTMLParser {
@@ -940,6 +940,7 @@ export namespace MarkdownParser {
940
940
  Inline<'html/tag'>,
941
941
  Parser<HTMLElement | string, Context, [
942
942
  InlineParser,
943
+ InlineParser,
943
944
  ]> {
944
945
  }
945
946
  export namespace TagParser {
@@ -956,6 +957,7 @@ export namespace MarkdownParser {
956
957
  Inline<'insertion'>,
957
958
  Parser<HTMLElement | string, Context, [
958
959
  InlineParser,
960
+ InlineParser,
959
961
  ]> {
960
962
  }
961
963
  export interface DeletionParser extends
@@ -963,6 +965,7 @@ export namespace MarkdownParser {
963
965
  Inline<'deletion'>,
964
966
  Parser<HTMLElement | string, Context, [
965
967
  InlineParser,
968
+ InlineParser,
966
969
  ]> {
967
970
  }
968
971
  export interface MarkParser extends
@@ -1137,9 +1140,9 @@ export namespace MarkdownParser {
1137
1140
  // ""
1138
1141
  Inline<'bracket'>,
1139
1142
  Parser<HTMLElement | string, Context, [
1140
- SourceParser.StrParser,
1141
1143
  SourceParser.StrParser,
1142
1144
  InlineParser,
1145
+ SourceParser.StrParser,
1143
1146
  InlineParser,
1144
1147
  InlineParser,
1145
1148
  InlineParser,
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.235.0",
3
+ "version": "0.235.3",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -448,12 +448,6 @@
448
448
  "which": "^2.0.2"
449
449
  },
450
450
  "dependencies": {
451
- "lru-cache": {
452
- "version": "7.7.2",
453
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
454
- "integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
455
- "dev": true
456
- },
457
451
  "mkdirp": {
458
452
  "version": "1.0.4",
459
453
  "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -1800,12 +1794,6 @@
1800
1794
  "unique-filename": "^1.1.1"
1801
1795
  },
1802
1796
  "dependencies": {
1803
- "lru-cache": {
1804
- "version": "7.7.2",
1805
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
1806
- "integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
1807
- "dev": true
1808
- },
1809
1797
  "mkdirp": {
1810
1798
  "version": "1.0.4",
1811
1799
  "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -1927,9 +1915,9 @@
1927
1915
  "dev": true
1928
1916
  },
1929
1917
  "caniuse-lite": {
1930
- "version": "1.0.30001322",
1931
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz",
1932
- "integrity": "sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew==",
1918
+ "version": "1.0.30001323",
1919
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz",
1920
+ "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==",
1933
1921
  "dev": true
1934
1922
  },
1935
1923
  "chalk": {
@@ -3033,9 +3021,9 @@
3033
3021
  "dev": true
3034
3022
  },
3035
3023
  "electron-to-chromium": {
3036
- "version": "1.4.100",
3037
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.100.tgz",
3038
- "integrity": "sha512-pNrSE2naf8fizl6/Uxq8UbKb8hU9EiYW4OzCYswosXoLV5NTMOUVKECNzDaHiUubsPq/kAckOzZd7zd8S8CHVw==",
3024
+ "version": "1.4.103",
3025
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz",
3026
+ "integrity": "sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==",
3039
3027
  "dev": true
3040
3028
  },
3041
3029
  "elliptic": {
@@ -7069,13 +7057,10 @@
7069
7057
  "dev": true
7070
7058
  },
7071
7059
  "lru-cache": {
7072
- "version": "6.0.0",
7073
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
7074
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
7075
- "dev": true,
7076
- "requires": {
7077
- "yallist": "^4.0.0"
7078
- }
7060
+ "version": "7.7.3",
7061
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz",
7062
+ "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==",
7063
+ "dev": true
7079
7064
  },
7080
7065
  "make-dir": {
7081
7066
  "version": "3.1.0",
@@ -7116,14 +7101,6 @@
7116
7101
  "promise-retry": "^2.0.1",
7117
7102
  "socks-proxy-agent": "^6.1.1",
7118
7103
  "ssri": "^8.0.1"
7119
- },
7120
- "dependencies": {
7121
- "lru-cache": {
7122
- "version": "7.7.2",
7123
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
7124
- "integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
7125
- "dev": true
7126
- }
7127
7104
  }
7128
7105
  },
7129
7106
  "make-iterator": {
@@ -8007,9 +7984,9 @@
8007
7984
  }
8008
7985
  },
8009
7986
  "npm-check-updates": {
8010
- "version": "12.5.4",
8011
- "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.4.tgz",
8012
- "integrity": "sha512-4+27zaTdieWgvPLaCZ/A6Q2WC1cYVcrc2SqVmLFYgkWBrKw1QkwpeV16FSvkFGZr3OdFyr7Dpjw8JRn4H2QxFw==",
7987
+ "version": "12.5.5",
7988
+ "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.5.tgz",
7989
+ "integrity": "sha512-7LH6KN6F1fZMtY4zNYAQPpJU1ToxZ6sSCxk948vrLIz97aNqmPLSX72MrmbOWwpyBgLCPbFJWY/k3zE18pmxfw==",
8013
7990
  "dev": true,
8014
7991
  "requires": {
8015
7992
  "chalk": "^4.1.2",
@@ -8021,7 +7998,7 @@
8021
7998
  "fp-and-or": "^0.1.3",
8022
7999
  "get-stdin": "^8.0.0",
8023
8000
  "globby": "^11.0.4",
8024
- "hosted-git-info": "^4.1.0",
8001
+ "hosted-git-info": "^5.0.0",
8025
8002
  "json-parse-helpfulerror": "^1.0.3",
8026
8003
  "jsonlines": "^0.1.1",
8027
8004
  "libnpmconfig": "^1.2.1",
@@ -8063,12 +8040,12 @@
8063
8040
  }
8064
8041
  },
8065
8042
  "hosted-git-info": {
8066
- "version": "4.1.0",
8067
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
8068
- "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
8043
+ "version": "5.0.0",
8044
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.0.0.tgz",
8045
+ "integrity": "sha512-rRnjWu0Bxj+nIfUOkz0695C0H6tRrN5iYIzYejb0tDEefe2AekHu/U5Kn9pEie5vsJqpNQU02az7TGSH3qpz4Q==",
8069
8046
  "dev": true,
8070
8047
  "requires": {
8071
- "lru-cache": "^6.0.0"
8048
+ "lru-cache": "^7.5.1"
8072
8049
  }
8073
8050
  },
8074
8051
  "locate-path": {
@@ -8149,12 +8126,6 @@
8149
8126
  "requires": {
8150
8127
  "lru-cache": "^7.5.1"
8151
8128
  }
8152
- },
8153
- "lru-cache": {
8154
- "version": "7.7.2",
8155
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
8156
- "integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
8157
- "dev": true
8158
8129
  }
8159
8130
  }
8160
8131
  },
@@ -9189,12 +9160,6 @@
9189
9160
  "lru-cache": "^7.5.1"
9190
9161
  }
9191
9162
  },
9192
- "lru-cache": {
9193
- "version": "7.7.2",
9194
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.2.tgz",
9195
- "integrity": "sha512-WkdIOIF7HkfVHXxKLjhH6lyAxSFoSO5NZpZS9cH8Oe5rAI2ZDrVmIweDAZUHqIhl0zasQUprVVR8uv2yggYYvw==",
9196
- "dev": true
9197
- },
9198
9163
  "normalize-package-data": {
9199
9164
  "version": "4.0.0",
9200
9165
  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.0.tgz",
@@ -9787,6 +9752,17 @@
9787
9752
  "dev": true,
9788
9753
  "requires": {
9789
9754
  "lru-cache": "^6.0.0"
9755
+ },
9756
+ "dependencies": {
9757
+ "lru-cache": {
9758
+ "version": "6.0.0",
9759
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
9760
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
9761
+ "dev": true,
9762
+ "requires": {
9763
+ "yallist": "^4.0.0"
9764
+ }
9765
+ }
9790
9766
  }
9791
9767
  },
9792
9768
  "semver-diff": {
@@ -10940,9 +10916,9 @@
10940
10916
  "dev": true
10941
10917
  },
10942
10918
  "typed-dom": {
10943
- "version": "0.0.249",
10944
- "resolved": "https://registry.npmjs.org/typed-dom/-/typed-dom-0.0.249.tgz",
10945
- "integrity": "sha512-9SS9P99g+/FKWgAYVjHjlhkgX31RXKBzwfI75DfHQPRXDPnl00rupgixuNqWiVIfniT/vy/yRSflc/zR7JRJaQ==",
10919
+ "version": "0.0.250",
10920
+ "resolved": "https://registry.npmjs.org/typed-dom/-/typed-dom-0.0.250.tgz",
10921
+ "integrity": "sha512-hjCpUI+E7St1bGVgyjYZww0ruhXLbPrcih6puElqXTIGHG9JHqd70p94RVilWup/mKoLnzeIdbFDYHLuloCfdQ==",
10946
10922
  "dev": true
10947
10923
  },
10948
10924
  "typedarray": {
@@ -10961,9 +10937,9 @@
10961
10937
  }
10962
10938
  },
10963
10939
  "typescript": {
10964
- "version": "4.6.2",
10965
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
10966
- "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
10940
+ "version": "4.6.3",
10941
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
10942
+ "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
10967
10943
  "dev": true
10968
10944
  },
10969
10945
  "ua-parser-js": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.235.0",
3
+ "version": "0.235.3",
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",
@@ -63,8 +63,8 @@
63
63
  "semver": "^7.3.5",
64
64
  "spica": "0.0.515",
65
65
  "tsify": "^5.0.4",
66
- "typed-dom": "0.0.249",
67
- "typescript": "4.6.2",
66
+ "typed-dom": "0.0.250",
67
+ "typescript": "4.6.3",
68
68
  "vinyl-buffer": "^1.0.1",
69
69
  "vinyl-source-stream": "^2.0.0"
70
70
  },
@@ -13,7 +13,7 @@ describe('Unit: combinator/context', () => {
13
13
  (s, context) => [[context.resources?.budget ?? NaN], s.slice(1)]));
14
14
 
15
15
  it('root', () => {
16
- const base: Context = { resources: { budget: 3 } };
16
+ const base: Context = { resources: { budget: 3, recursion: 1 } };
17
17
  const ctx: Context = {};
18
18
  assert.deepStrictEqual(reset(base, parser)('123', ctx), [[3, 2, 1], '']);
19
19
  assert(base.resources?.budget === 3);
@@ -24,8 +24,8 @@ describe('Unit: combinator/context', () => {
24
24
  });
25
25
 
26
26
  it('node', () => {
27
- const base: Context = { resources: { budget: 3 } };
28
- const ctx: Context = { resources: { budget: 1 } };
27
+ const base: Context = { resources: { budget: 3, recursion: 1 } };
28
+ const ctx: Context = { resources: { budget: 1, recursion: 1 } };
29
29
  assert.deepStrictEqual(reset(base, parser)('1', ctx), [[1], '']);
30
30
  assert(base.resources?.budget === 3);
31
31
  assert(ctx.resources?.budget === 0);
@@ -41,7 +41,7 @@ describe('Unit: combinator/context', () => {
41
41
 
42
42
  it('', () => {
43
43
  const base: Context = { state: true };
44
- const ctx: Context = { resources: { budget: 3 } };
44
+ const ctx: Context = { resources: { budget: 3, recursion: 1 } };
45
45
  assert.deepStrictEqual(context(base, parser)('123', ctx), [[true, true, true], '']);
46
46
  assert(ctx.resources?.budget === 0);
47
47
  assert(ctx.state === undefined);
@@ -6,10 +6,13 @@ export function creator(cost: number | Parser<unknown>, parser?: Parser<unknown>
6
6
  if (typeof cost === 'function') return creator(1, cost);
7
7
  assert(cost > 0);
8
8
  return (source, context) => {
9
- const { resources } = context;
10
- if (resources?.budget! <= 0) throw new Error('Too many creations.');
9
+ const { resources = { budget: 1, recursion: 1 } } = context;
10
+ if (resources.budget <= 0) throw new Error('Too many creations.');
11
+ if (resources.recursion <= 0) throw new Error('Too much recursion.');
12
+ --resources.recursion;
11
13
  const result = parser!(source, context);
12
- if (result && resources) {
14
+ ++resources.recursion;
15
+ if (result) {
13
16
  resources.budget -= cost;
14
17
  }
15
18
  return result;
@@ -1,7 +1,6 @@
1
1
  import { undefined } from 'spica/global';
2
2
  import { Parser, Result, Ctx, Tree, Context, SubParsers, SubTree, IntermediateParser, eval, exec, check } from '../../data/parser';
3
3
  import { fmap } from '../monad/fmap';
4
- import { creator } from './resource';
5
4
  import { unshift, push } from 'spica/array';
6
5
 
7
6
  export function surround<P extends Parser<unknown>, S = string>(
@@ -69,14 +68,14 @@ export function surround<T>(
69
68
  function match(pattern: string | RegExp): (source: string, context: Ctx) => [never[], string] | undefined {
70
69
  switch (typeof pattern) {
71
70
  case 'string':
72
- return creator(source => source.slice(0, pattern.length) === pattern ? [[], source.slice(pattern.length)] : undefined);
71
+ return source => source.slice(0, pattern.length) === pattern ? [[], source.slice(pattern.length)] : undefined;
73
72
  case 'object':
74
- return creator(source => {
73
+ return source => {
75
74
  const m = source.match(pattern);
76
75
  return m
77
76
  ? [[], source.slice(m[0].length)]
78
77
  : undefined;
79
- });
78
+ };
80
79
  }
81
80
  }
82
81
 
@@ -14,7 +14,7 @@ export function inits<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
14
14
  const result = parsers[i](rest, context);
15
15
  assert(check(rest, result));
16
16
  if (!result) break;
17
- assert(!context?.delimiters?.stack.some(sig => context.delimiters!.matchers[sig](rest)));
17
+ assert(!context?.delimiters?.match(rest));
18
18
  nodes = nodes
19
19
  ? push(nodes, eval(result))
20
20
  : eval(result);
@@ -14,7 +14,7 @@ export function sequence<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D
14
14
  const result = parsers[i](rest, context);
15
15
  assert(check(rest, result));
16
16
  if (!result) return;
17
- assert(!context?.delimiters?.stack.some(sig => context.delimiters!.matchers[sig](rest)));
17
+ assert(!context?.delimiters?.match(rest));
18
18
  nodes = nodes
19
19
  ? push(nodes, eval(result))
20
20
  : eval(result);
@@ -1,5 +1,5 @@
1
1
  import { undefined } from 'spica/global';
2
- import { Parser, eval, exec, check } from '../parser';
2
+ import { Parser, Delimiters, eval, exec, check } from '../parser';
3
3
  import { memoize, reduce } from 'spica/memoize';
4
4
  import { push } from 'spica/array';
5
5
 
@@ -13,19 +13,18 @@ const signature = (pattern: string | RegExp | undefined): string => {
13
13
  return `r/${pattern.source}/${pattern.flags}`;
14
14
  }
15
15
  };
16
- const [matcher, delimiter] = [...Array(2)].map(() =>
17
- memoize(
18
- (pattern: string | RegExp | undefined): (source: string) => boolean => {
19
- switch (typeof pattern) {
20
- case 'undefined':
21
- return () => false;
22
- case 'string':
23
- return source => source.slice(0, pattern.length) === pattern;
24
- case 'object':
25
- return reduce(source => pattern.test(source));
26
- }
27
- },
28
- signature));
16
+ const matcher = memoize(
17
+ (pattern: string | RegExp | undefined): (source: string) => boolean => {
18
+ switch (typeof pattern) {
19
+ case 'undefined':
20
+ return () => false;
21
+ case 'string':
22
+ return source => source.slice(0, pattern.length) === pattern;
23
+ case 'object':
24
+ return reduce(source => pattern.test(source));
25
+ }
26
+ },
27
+ signature);
29
28
 
30
29
  export function some<P extends Parser<unknown>>(parser: P, until?: string | RegExp | number, deep?: string | RegExp, limit?: number): P;
31
30
  export function some<T>(parser: Parser<T>, until?: string | RegExp | number, deep?: string | RegExp, limit = -1): Parser<T> {
@@ -34,25 +33,24 @@ export function some<T>(parser: Parser<T>, until?: string | RegExp | number, dee
34
33
  assert(deep instanceof RegExp ? !deep.flags.match(/[gmy]/) && deep.source.startsWith('^') : true);
35
34
  if (typeof until === 'number') return some(parser, undefined, deep, until);
36
35
  const match = matcher(until);
37
- const delim = delimiter(deep);
38
- const sig = signature(deep);
36
+ const delimiter = {
37
+ signature: signature(deep),
38
+ matcher: matcher(deep),
39
+ } as const;
39
40
  return (source, context) => {
40
41
  if (source === '') return;
41
42
  let rest = source;
42
43
  let nodes: T[] | undefined;
43
- if (context && deep) {
44
+ if (deep && context) {
44
45
  // bracket > annotation > bracket > reference > bracket > link > media | bracket
45
46
  // bracket > annotation > bracket > reference > bracket > index > bracket
46
- context.delimiters ??= { stack: [], matchers: {} };
47
- context.delimiters.stack.push(sig);
48
- context.delimiters.matchers[sig] ??= delim;
49
- assert(context.delimiters.matchers[sig] === delim);
47
+ context.delimiters ??= new Delimiters();
48
+ context.delimiters.push(delimiter);
50
49
  }
51
- const { stack, matchers } = context.delimiters ?? {};
52
50
  while (true) {
53
51
  if (rest === '') break;
54
52
  if (match(rest)) break;
55
- if (stack?.some(sig => matchers![sig](rest))) break;
53
+ if (context.delimiters?.match(rest)) break;
56
54
  const result = parser(rest, context);
57
55
  assert.doesNotThrow(() => limit < 0 && check(rest, result));
58
56
  if (!result) break;
@@ -62,8 +60,8 @@ export function some<T>(parser: Parser<T>, until?: string | RegExp | number, dee
62
60
  rest = exec(result);
63
61
  if (limit >= 0 && source.length - rest.length > limit) break;
64
62
  }
65
- if (context && deep) {
66
- stack?.pop();
63
+ if (deep && context.delimiters) {
64
+ context.delimiters.pop();
67
65
  }
68
66
  assert(rest.length <= source.length);
69
67
  return nodes && rest.length < source.length
@@ -1,19 +1,16 @@
1
- export interface Ctx {
2
- readonly resources?: {
3
- budget: number;
4
- };
5
- delimiters?: {
6
- readonly stack: string[];
7
- readonly matchers: Record<string, (source: string) => boolean>;
8
- };
9
- }
10
-
11
1
  export type Parser<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
12
2
  = (source: string, context: C) => Result<T, C, D>;
13
3
  export type Result<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
14
4
  = readonly [T[], string, C, D]
15
5
  | readonly [T[], string]
16
6
  | undefined;
7
+ export interface Ctx {
8
+ readonly resources?: {
9
+ budget: number;
10
+ recursion: number;
11
+ };
12
+ delimiters?: Delimiters;
13
+ }
17
14
  export type Tree<P extends Parser<unknown>> = P extends Parser<infer T> ? T : never;
18
15
  export type SubParsers<P extends Parser<unknown>> = P extends Parser<unknown, any, infer D> ? D : never;
19
16
  export type Context<P extends Parser<unknown>> = P extends Parser<unknown, infer C> ? C : never;
@@ -22,6 +19,32 @@ export type IntermediateParser<P extends Parser<unknown>> = Parser<SubTree<P>, C
22
19
  type ExtractSubTree<D extends Parser<unknown>[]> = ExtractSubParser<D> extends infer T ? T extends Parser<infer U> ? U : never : never;
23
20
  type ExtractSubParser<D extends Parser<unknown>[]> = D extends (infer P)[] ? P extends Parser<unknown> ? P : never : never;
24
21
 
22
+ export class Delimiters {
23
+ private readonly stack: string[] = [];
24
+ private readonly matchers: Record<string, (source: string) => boolean> = {};
25
+ public push(delimiter: { readonly signature: string; readonly matcher: (source: string) => boolean; }): void {
26
+ const { signature, matcher } = delimiter;
27
+ this.stack.push(signature);
28
+ this.matchers[signature] ??= matcher;
29
+ assert(this.matchers[signature] === matcher);
30
+ }
31
+ public pop(): void {
32
+ assert(this.stack.length > 0);
33
+ this.stack.pop();
34
+ }
35
+ public match(source: string): boolean {
36
+ const { stack, matchers } = this;
37
+ const log = {};
38
+ for (let i = 0; i < stack.length; ++i) {
39
+ const sig = stack[i];
40
+ if (sig in log) continue;
41
+ if (matchers[sig](source)) return true;
42
+ log[sig] = false;
43
+ }
44
+ return false;
45
+ }
46
+ }
47
+
25
48
  export { eval_ as eval };
26
49
  function eval_<T>(result: NonNullable<Result<T>>, default_?: T[]): T[];
27
50
  function eval_<T>(result: Result<T>, default_: T[]): T[];
@@ -34,7 +34,7 @@ describe('Unit: parser/api/bind', () => {
34
34
  assert.deepStrictEqual(
35
35
  inspect(iter),
36
36
  [
37
- '<h1 class="error" translate="no">Error: Too large input over 1,000,000 bytes.</h1>',
37
+ '<h1 class="error">Error: Too large input over 1,000,000 bytes.</h1>',
38
38
  `<pre class="error" translate="no">${'\n'.repeat(997)}...</pre>`,
39
39
  ]);
40
40
  });
@@ -46,9 +46,9 @@ describe('Unit: parser/api/bind', () => {
46
46
  assert.deepStrictEqual(
47
47
  inspect(iter, 3),
48
48
  [
49
- '<h1 class="error" translate="no">Error: Too large segment over 100,000 bytes.</h1>',
49
+ '<h1 class="error">Error: Too large segment over 100,000 bytes.</h1>',
50
50
  `<pre class="error" translate="no">${'\n'.repeat(997)}...</pre>`,
51
- '<h1 class="error" translate="no">Error: Too large segment over 100,000 bytes.</h1>',
51
+ '<h1 class="error">Error: Too large segment over 100,000 bytes.</h1>',
52
52
  ]);
53
53
  });
54
54
 
@@ -118,7 +118,7 @@ describe('Unit: parser/api/parse', () => {
118
118
  '<p><a href="https://source/hashtags/a" target="_blank" class="hashtag">#a</a></p>',
119
119
  '<p><a href="https://domain/hashtags/a" target="_blank" class="hashtag">#domain/a</a></p>',
120
120
  '<p><a class="index" href="#index:a">a</a></p>',
121
- '<figure data-label="$-a" data-group="$" data-number="1" id="label:$-a"><div class="figcontent"><div class="math" translate="no">$$\n$$</div></div><span class="figindex">(1)</span><figcaption></figcaption></figure>',
121
+ '<figure data-label="$-a" data-group="$" data-number="1" id="label:$-a"><div><div class="math" translate="no">$$\n$$</div></div><figcaption><span class="figindex">(1)</span></figcaption></figure>',
122
122
  '<p><a class="label" data-label="$-a" href="#label:$-a">(1)</a></p>',
123
123
  '<p><sup class="annotation" id="annotation:ref:1" title="a"><span hidden="">a</span><a href="#annotation:def:1">*1</a></sup></p>',
124
124
  '<p><a href="https://source/x/a" target="_blank">a</a></p>',
@@ -201,7 +201,7 @@ describe('Unit: parser/api/parse', () => {
201
201
  assert.deepStrictEqual(
202
202
  [...parse('$-a\n$$\n$$\n\n(($-a[[b]][[c*d*]]))', { footnotes }).children].map(el => el.outerHTML),
203
203
  [
204
- '<figure data-label="$-a" data-group="$" data-number="1" id="label:$-a"><div class="figcontent"><div class="math" translate="no">$$\n$$</div></div><span class="figindex">(1)</span><figcaption></figcaption></figure>',
204
+ '<figure data-label="$-a" data-group="$" data-number="1" id="label:$-a"><div><div class="math" translate="no">$$\n$$</div></div><figcaption><span class="figindex">(1)</span></figcaption></figure>',
205
205
  '<p><sup class="annotation" id="annotation:ref:1" title="(1)[1][2]"><span hidden=""><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" id="reference:ref:1" title="b"><span hidden="">b</span><a href="#reference:def:1">[1]</a></sup><sup class="reference" id="reference:ref:2" title="cd"><span hidden="">c<em>d</em></span><a href="#reference:def:2">[2]</a></sup></span><a href="#annotation:def:1">*1</a></sup></p>',
206
206
  ]);
207
207
  assert.deepStrictEqual(
@@ -218,10 +218,17 @@ describe('Unit: parser/api/parse', () => {
218
218
  ['<p>a<span class="linebreak"> </span>b</p>']);
219
219
  });
220
220
 
221
- it('reset', () => {
221
+ it('recursion', () => {
222
222
  assert.deepStrictEqual(
223
- [...parse(`"${'('.repeat(10000)}\n\n"`).children].slice(2).map(el => el.outerHTML),
224
- ['<p>"</p>']);
223
+ [...parse('('.repeat(199)).children].map(el => el.outerHTML),
224
+ [`<p>${'('.repeat(199)}</p>`]);
225
+ assert.deepStrictEqual(
226
+ [...parse('('.repeat(200) + '\n\na').children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
227
+ [
228
+ '<h1 id="error:rnd" class="error">Error: Too much recursion.</h1>',
229
+ `<pre class="error" translate="no">${'('.repeat(200)}\n</pre>`,
230
+ '<p>a</p>',
231
+ ]);
225
232
  });
226
233
 
227
234
  });
@@ -95,7 +95,7 @@ describe('Unit: parser/block/blockquote', () => {
95
95
  assert.deepStrictEqual(inspect(parser('!>\n> a')), [['<blockquote><section><p>a</p><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
96
96
  assert.deepStrictEqual(inspect(parser('!>> ## a\n> ## a')), [['<blockquote><blockquote><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
97
97
  assert.deepStrictEqual(inspect(parser('!>> ~ a\n> ~ a')), [['<blockquote><blockquote><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
98
- assert.deepStrictEqual(inspect(parser('!>> ~~~figure $fig-a\n>> > \n>>\n~~~\n> ~~~figure $fig-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1. </span><figcaption><a class="index">a</a></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
98
+ assert.deepStrictEqual(inspect(parser('!>> ~~~figure $fig-a\n>> > \n>>\n~~~\n> ~~~figure $fig-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div><blockquote></blockquote></div><figcaption><span class="figindex">Fig. 1. </span></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div><blockquote></blockquote></div><figcaption><span class="figindex">Fig. 1. </span><a class="index">a</a></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
99
99
  assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li>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></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>'], '']);
100
100
  });
101
101
 
@@ -16,7 +16,7 @@ describe('Unit: parser/block/extension/aside', () => {
16
16
  it('valid', () => {
17
17
  assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
18
18
  assert.deepStrictEqual(inspect(parser('~~~aside\n## 0\n~~~')), [['<aside id="index:0" class="aside"><h2>0</h2><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
19
- assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n\n$-0.0\n\n## 1\n\n$fig-a\n> \n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><figure data-label="$-0.0" data-group="$" hidden="" data-number="0.0"></figure><h2>1</h2><figure data-label="fig-a" data-group="fig" data-number="1.1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1.1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
19
+ assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n\n$-0.0\n\n## 1\n\n$fig-a\n> \n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><figure data-label="$-0.0" data-group="$" hidden="" data-number="0.0"></figure><h2>1</h2><figure data-label="fig-a" data-group="fig" data-number="1.1"><div><blockquote></blockquote></div><figcaption><span class="figindex">Fig. 1.1. </span></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
20
20
  });
21
21
 
22
22
  });
@@ -19,8 +19,8 @@ describe('Unit: parser/block/extension/example', () => {
19
19
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
20
20
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\na\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">a</pre><hr><section><p>a</p><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
21
21
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n*a\nb*\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">*a\nb*</pre><hr><section><p><em>a<br>b</em></p><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
22
- assert.deepStrictEqual(inspect(parser('~~~example/markdown\n$fig-a\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">$fig-a\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
23
- assert.deepStrictEqual(inspect(parser('~~~example/markdown\n[$fig-a]\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">[$fig-a]\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
22
+ assert.deepStrictEqual(inspect(parser('~~~example/markdown\n$fig-a\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">$fig-a\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><figcaption><span class="figindex">Fig. 1. </span></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
23
+ assert.deepStrictEqual(inspect(parser('~~~example/markdown\n[$fig-a]\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">[$fig-a]\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><figcaption><span class="figindex">Fig. 1. </span></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n## a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">## a</pre><hr><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
25
25
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n~ a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">~ a</pre><hr><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
26
26
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><sup class="reference disabled" title="b"><span hidden="">b</span><a>[1]</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"><li>b<sup><a>^1</a></sup></li></ol></section></aside>'], '']);