securemark 0.236.0 → 0.237.2

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 (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/securemark.js +184 -99
  3. package/karma.conf.js +1 -1
  4. package/markdown.d.ts +9 -10
  5. package/package-lock.json +81 -47
  6. package/package.json +1 -1
  7. package/src/parser/api/bind.ts +7 -3
  8. package/src/parser/api/parse.test.ts +2 -2
  9. package/src/parser/api/parse.ts +8 -11
  10. package/src/parser/block/blockquote.test.ts +1 -1
  11. package/src/parser/block/codeblock.test.ts +5 -2
  12. package/src/parser/block/codeblock.ts +43 -25
  13. package/src/parser/block/dlist.ts +1 -3
  14. package/src/parser/block/extension/aside.test.ts +1 -1
  15. package/src/parser/block/extension/aside.ts +1 -1
  16. package/src/parser/block/extension/example.test.ts +2 -2
  17. package/src/parser/block/extension/example.ts +1 -1
  18. package/src/parser/block/extension/fig.test.ts +22 -20
  19. package/src/parser/block/extension/figure.test.ts +33 -33
  20. package/src/parser/block/extension/figure.ts +26 -1
  21. package/src/parser/block/extension/message.ts +1 -1
  22. package/src/parser/block/extension/placeholder.ts +1 -1
  23. package/src/parser/block/extension/table.ts +1 -1
  24. package/src/parser/block/extension.ts +1 -1
  25. package/src/parser/block/heading.test.ts +1 -1
  26. package/src/parser/block/heading.ts +11 -7
  27. package/src/parser/block/mathblock.ts +1 -1
  28. package/src/parser/block/olist.test.ts +8 -0
  29. package/src/parser/block/olist.ts +6 -6
  30. package/src/parser/block/reply/cite.test.ts +4 -0
  31. package/src/parser/block/reply/cite.ts +1 -0
  32. package/src/parser/block/ulist.test.ts +8 -0
  33. package/src/parser/block/ulist.ts +6 -6
  34. package/src/parser/inline/comment.ts +1 -1
  35. package/src/parser/inline/extension/indexee.ts +8 -8
  36. package/src/parser/inline.ts +2 -0
  37. package/src/parser/processor/figure.test.ts +70 -46
  38. package/src/parser/processor/figure.ts +58 -21
  39. package/src/parser/processor/footnote.ts +1 -1
  40. package/src/util/quote.ts +1 -0
package/karma.conf.js CHANGED
@@ -7,7 +7,7 @@ module.exports = function (config) {
7
7
  { pattern: 'https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js', watched: false, served: false, included: true },
8
8
  { pattern: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/prism.js', watched: false, served: false, included: true },
9
9
  { pattern: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/plugins/autoloader/prism-autoloader.min.js', watched: false, served: false, included: true },
10
- { pattern: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.1.2/es5/tex-chtml.min.js', watched: false, served: false, included: true },
10
+ { pattern: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-chtml.min.js', watched: false, served: false, included: true },
11
11
  { pattern: 'https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.2.2/purify.js', watched: false, served: false, included: true },
12
12
  { pattern: 'node_modules/power-assert/build/power-assert.js', watched: true, served: true, included: true },
13
13
  { pattern: 'dist/*.test.js', watched: true, served: true, included: true }
package/markdown.d.ts CHANGED
@@ -133,7 +133,10 @@ export namespace MarkdownParser {
133
133
  Parser<HTMLLIElement, Context, [
134
134
  Parser<HTMLElement | string, Context, [
135
135
  InlineParser,
136
- InlineParser,
136
+ Parser<HTMLElement | string, Context, [
137
+ InlineParser.ExtensionParser.IndexerParser,
138
+ InlineParser,
139
+ ]>,
137
140
  ]>,
138
141
  Parser<HTMLUListElement | HTMLOListElement, Context, [
139
142
  UListParser,
@@ -165,7 +168,10 @@ export namespace MarkdownParser {
165
168
  Parser<HTMLLIElement, Context, [
166
169
  Parser<HTMLElement | string, Context, [
167
170
  InlineParser,
168
- InlineParser,
171
+ Parser<HTMLElement | string, Context, [
172
+ InlineParser.ExtensionParser.IndexerParser,
173
+ InlineParser,
174
+ ]>,
169
175
  ]>,
170
176
  Parser<HTMLUListElement | HTMLOListElement, Context, [
171
177
  UListParser,
@@ -432,14 +438,6 @@ export namespace MarkdownParser {
432
438
  InlineParser.ExtensionParser.LabelParser,
433
439
  ]> {
434
440
  }
435
- export namespace FigbaseParser {
436
- export interface SegmentParser extends
437
- Block<'extension/figbase/segment'>,
438
- Parser<never, Context, [
439
- InlineParser.ExtensionParser.LabelParser.SegmentParser,
440
- ]> {
441
- }
442
- }
443
441
  export interface TableParser extends
444
442
  // ~~~table
445
443
  // -/-
@@ -577,6 +575,7 @@ export namespace MarkdownParser {
577
575
  Parser<HTMLAnchorElement, Context, [
578
576
  InlineParser.AutolinkParser.AnchorParser,
579
577
  Parser<HTMLAnchorElement, Context, []>,
578
+ Parser<HTMLAnchorElement, Context, []>,
580
579
  ]>,
581
580
  ]> {
582
581
  }
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.236.0",
3
+ "version": "0.237.2",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -783,6 +783,12 @@
783
783
  "ms": "2.1.2"
784
784
  }
785
785
  },
786
+ "depd": {
787
+ "version": "1.1.2",
788
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
789
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
790
+ "dev": true
791
+ },
786
792
  "ms": {
787
793
  "version": "2.1.2",
788
794
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1420,21 +1426,23 @@
1420
1426
  "dev": true
1421
1427
  },
1422
1428
  "body-parser": {
1423
- "version": "1.19.2",
1424
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
1425
- "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
1429
+ "version": "1.20.0",
1430
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
1431
+ "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
1426
1432
  "dev": true,
1427
1433
  "requires": {
1428
1434
  "bytes": "3.1.2",
1429
1435
  "content-type": "~1.0.4",
1430
1436
  "debug": "2.6.9",
1431
- "depd": "~1.1.2",
1432
- "http-errors": "1.8.1",
1437
+ "depd": "2.0.0",
1438
+ "destroy": "1.2.0",
1439
+ "http-errors": "2.0.0",
1433
1440
  "iconv-lite": "0.4.24",
1434
- "on-finished": "~2.3.0",
1435
- "qs": "6.9.7",
1436
- "raw-body": "2.4.3",
1437
- "type-is": "~1.6.18"
1441
+ "on-finished": "2.4.1",
1442
+ "qs": "6.10.3",
1443
+ "raw-body": "2.5.1",
1444
+ "type-is": "~1.6.18",
1445
+ "unpipe": "1.0.0"
1438
1446
  }
1439
1447
  },
1440
1448
  "boxen": {
@@ -1915,9 +1923,9 @@
1915
1923
  "dev": true
1916
1924
  },
1917
1925
  "caniuse-lite": {
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==",
1926
+ "version": "1.0.30001324",
1927
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001324.tgz",
1928
+ "integrity": "sha512-/eYp1J6zYh1alySQB4uzYFkLmxxI8tk0kxldbNHXp8+v+rdMKdUBNjRLz7T7fz6Iox+1lIdYpc7rq6ZcXfTukg==",
1921
1929
  "dev": true
1922
1930
  },
1923
1931
  "chalk": {
@@ -2307,9 +2315,9 @@
2307
2315
  }
2308
2316
  },
2309
2317
  "concurrently": {
2310
- "version": "7.0.0",
2311
- "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.0.0.tgz",
2312
- "integrity": "sha512-WKM7PUsI8wyXpF80H+zjHP32fsgsHNQfPLw/e70Z5dYkV7hF+rf8q3D+ScWJIEr57CpkO3OWBko6hwhQLPR8Pw==",
2318
+ "version": "7.1.0",
2319
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz",
2320
+ "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==",
2313
2321
  "dev": true,
2314
2322
  "requires": {
2315
2323
  "chalk": "^4.1.0",
@@ -2725,9 +2733,9 @@
2725
2733
  "dev": true
2726
2734
  },
2727
2735
  "depd": {
2728
- "version": "1.1.2",
2729
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
2730
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
2736
+ "version": "2.0.0",
2737
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
2738
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
2731
2739
  "dev": true
2732
2740
  },
2733
2741
  "deps-sort": {
@@ -2858,6 +2866,12 @@
2858
2866
  "minimalistic-assert": "^1.0.0"
2859
2867
  }
2860
2868
  },
2869
+ "destroy": {
2870
+ "version": "1.2.0",
2871
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
2872
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
2873
+ "dev": true
2874
+ },
2861
2875
  "detect-file": {
2862
2876
  "version": "1.0.0",
2863
2877
  "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
@@ -4299,6 +4313,23 @@
4299
4313
  "parseurl": "~1.3.3",
4300
4314
  "statuses": "~1.5.0",
4301
4315
  "unpipe": "~1.0.0"
4316
+ },
4317
+ "dependencies": {
4318
+ "on-finished": {
4319
+ "version": "2.3.0",
4320
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
4321
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
4322
+ "dev": true,
4323
+ "requires": {
4324
+ "ee-first": "1.1.1"
4325
+ }
4326
+ },
4327
+ "statuses": {
4328
+ "version": "1.5.0",
4329
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
4330
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
4331
+ "dev": true
4332
+ }
4302
4333
  }
4303
4334
  },
4304
4335
  "find-parent-dir": {
@@ -5662,15 +5693,15 @@
5662
5693
  "dev": true
5663
5694
  },
5664
5695
  "http-errors": {
5665
- "version": "1.8.1",
5666
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
5667
- "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
5696
+ "version": "2.0.0",
5697
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
5698
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
5668
5699
  "dev": true,
5669
5700
  "requires": {
5670
- "depd": "~1.1.2",
5701
+ "depd": "2.0.0",
5671
5702
  "inherits": "2.0.4",
5672
5703
  "setprototypeof": "1.2.0",
5673
- "statuses": ">= 1.5.0 < 2",
5704
+ "statuses": "2.0.1",
5674
5705
  "toidentifier": "1.0.1"
5675
5706
  }
5676
5707
  },
@@ -7987,15 +8018,15 @@
7987
8018
  }
7988
8019
  },
7989
8020
  "npm-check-updates": {
7990
- "version": "12.5.5",
7991
- "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.5.tgz",
7992
- "integrity": "sha512-7LH6KN6F1fZMtY4zNYAQPpJU1ToxZ6sSCxk948vrLIz97aNqmPLSX72MrmbOWwpyBgLCPbFJWY/k3zE18pmxfw==",
8021
+ "version": "12.5.7",
8022
+ "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.7.tgz",
8023
+ "integrity": "sha512-WDkqPBevmgphV1UH3FImsDEpTAq2UFvnMZC3GdXPknE2VL701kfKylnae8IA9ZeYfm/uU0249N9gjMXqA/9y3w==",
7993
8024
  "dev": true,
7994
8025
  "requires": {
7995
8026
  "chalk": "^4.1.2",
7996
8027
  "cint": "^8.2.1",
7997
8028
  "cli-table": "^0.3.11",
7998
- "commander": "^9.0.0",
8029
+ "commander": "^9.1.0",
7999
8030
  "fast-memoize": "^2.5.2",
8000
8031
  "find-up": "5.0.0",
8001
8032
  "fp-and-or": "^0.1.3",
@@ -8008,11 +8039,11 @@
8008
8039
  "lodash": "^4.17.21",
8009
8040
  "minimatch": "^5.0.1",
8010
8041
  "p-map": "^4.0.0",
8011
- "pacote": "^13.0.3",
8042
+ "pacote": "^13.0.5",
8012
8043
  "parse-github-url": "^1.0.2",
8013
8044
  "progress": "^2.0.3",
8014
8045
  "prompts": "^2.4.2",
8015
- "rc-config-loader": "^4.0.0",
8046
+ "rc-config-loader": "^4.1.0",
8016
8047
  "remote-git-tags": "^3.0.0",
8017
8048
  "rimraf": "^3.0.2",
8018
8049
  "semver": "^7.3.5",
@@ -8328,9 +8359,9 @@
8328
8359
  }
8329
8360
  },
8330
8361
  "on-finished": {
8331
- "version": "2.3.0",
8332
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
8333
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
8362
+ "version": "2.4.1",
8363
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
8364
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
8334
8365
  "dev": true,
8335
8366
  "requires": {
8336
8367
  "ee-first": "1.1.1"
@@ -9009,10 +9040,13 @@
9009
9040
  "dev": true
9010
9041
  },
9011
9042
  "qs": {
9012
- "version": "6.9.7",
9013
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
9014
- "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
9015
- "dev": true
9043
+ "version": "6.10.3",
9044
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
9045
+ "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
9046
+ "dev": true,
9047
+ "requires": {
9048
+ "side-channel": "^1.0.4"
9049
+ }
9016
9050
  },
9017
9051
  "querystring": {
9018
9052
  "version": "0.2.0",
@@ -9058,13 +9092,13 @@
9058
9092
  "dev": true
9059
9093
  },
9060
9094
  "raw-body": {
9061
- "version": "2.4.3",
9062
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
9063
- "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
9095
+ "version": "2.5.1",
9096
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
9097
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
9064
9098
  "dev": true,
9065
9099
  "requires": {
9066
9100
  "bytes": "3.1.2",
9067
- "http-errors": "1.8.1",
9101
+ "http-errors": "2.0.0",
9068
9102
  "iconv-lite": "0.4.24",
9069
9103
  "unpipe": "1.0.0"
9070
9104
  }
@@ -9090,9 +9124,9 @@
9090
9124
  }
9091
9125
  },
9092
9126
  "rc-config-loader": {
9093
- "version": "4.0.0",
9094
- "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.0.0.tgz",
9095
- "integrity": "sha512-//LRTblJEcqbmmro1GCmZ39qZXD+JqzuD8Y5/IZU3Dhp3A1Yr0Xn68ks8MQ6qKfKvYCWDveUmRDKDA40c+sCXw==",
9127
+ "version": "4.1.0",
9128
+ "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.0.tgz",
9129
+ "integrity": "sha512-aW+kX4qy0CiM9L4fG4Us3oEOpIrOrXzWykAn+xldD07Y9PXWjTH744oHbv0Kc9ZwWaylw3jMjxaf14RgStrNrA==",
9096
9130
  "dev": true,
9097
9131
  "requires": {
9098
9132
  "debug": "^4.1.1",
@@ -10329,9 +10363,9 @@
10329
10363
  }
10330
10364
  },
10331
10365
  "statuses": {
10332
- "version": "1.5.0",
10333
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
10334
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
10366
+ "version": "2.0.1",
10367
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
10368
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
10335
10369
  "dev": true
10336
10370
  },
10337
10371
  "stream-browserify": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.236.0",
3
+ "version": "0.237.2",
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",
@@ -1,5 +1,5 @@
1
1
  import { undefined, location } from 'spica/global';
2
- import { ObjectAssign } from 'spica/alias';
2
+ import { ObjectAssign, ObjectCreate } from 'spica/alias';
3
3
  import { ParserSettings, Progress } from '../../..';
4
4
  import { MarkdownParser } from '../../../markdown';
5
5
  import { eval } from '../../combinator/data/parser';
@@ -21,7 +21,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
21
21
  nearest: (position: number) => HTMLElement | undefined;
22
22
  index: (block: HTMLElement) => number;
23
23
  } {
24
- let context: MarkdownParser.Context = ObjectAssign({ ...settings }, {
24
+ const context: MarkdownParser.Context = ObjectAssign(ObjectCreate(settings), {
25
25
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
26
26
  footnotes: undefined,
27
27
  chunk: undefined,
@@ -44,7 +44,11 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
44
44
  if (settings.chunk && revision) throw new Error('Chunks cannot be updated.');
45
45
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
46
46
  source = normalize(validate(source, MAX_INPUT_SIZE) ? source : source.slice(0, MAX_INPUT_SIZE + 1));
47
- context = ObjectAssign({ ...context }, { url: url ? new ReadonlyURL(url as ':') : undefined });
47
+ ObjectAssign<MarkdownParser.Context, MarkdownParser.Context>(
48
+ context,
49
+ {
50
+ url: url ? new ReadonlyURL(url as ':') : undefined,
51
+ });
48
52
  const rev = revision = Symbol();
49
53
  const sourceSegments: string[] = [];
50
54
  for (const seg of segment(source)) {
@@ -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><div class="math" translate="no">$$\n$$</div></div><figcaption><span class="figindex">(1)</span></figcaption></figure>',
121
+ '<figure data-type="math" 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><div class="math" translate="no">$$\n$$</div></div><figcaption><span class="figindex">(1)</span></figcaption></figure>',
204
+ '<figure data-type="math" 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(
@@ -1,5 +1,4 @@
1
1
  import { undefined, location } from 'spica/global';
2
- import { ObjectAssign, ObjectCreate } from 'spica/alias';
3
2
  import { ParserOptions } from '../../..';
4
3
  import { MarkdownParser } from '../../../markdown';
5
4
  import { eval } from '../../combinator/data/parser';
@@ -22,16 +21,14 @@ export function parse(source: string, opts: Options = {}, context?: MarkdownPars
22
21
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
23
22
  source = !context ? normalize(source) : source;
24
23
  assert(!context?.delimiters);
25
- context = context && url === '' && context.id === opts.id
26
- ? context
27
- : ObjectAssign(ObjectCreate(context ?? {}), opts, {
28
- host: opts.host ?? context?.host ?? new ReadonlyURL(location.pathname, location.origin),
29
- url: url ? new ReadonlyURL(url as ':') : context?.url,
30
- id: opts.id ?? context?.id,
31
- footnotes: undefined,
32
- test: undefined,
33
- });
34
- assert(context.caches === arguments[2]?.caches);
24
+ context = {
25
+ url: url ? new ReadonlyURL(url as ':') : context?.url,
26
+ host: opts.host ?? context?.host ?? new ReadonlyURL(location.pathname, location.origin),
27
+ caches: context?.caches,
28
+ footnotes: undefined,
29
+ test: undefined,
30
+ ...opts,
31
+ };
35
32
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
36
33
  const node = frag();
37
34
  let index = 0;
@@ -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><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>'], '']);
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-type="quote" 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-type="quote" 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
 
@@ -47,7 +47,7 @@ describe('Unit: parser/block/codeblock', () => {
47
47
  it('attribute', () => {
48
48
  assert.deepStrictEqual(inspect(parser('```0\n```')), [['<pre class="code language-0" translate="no" data-lang="0"></pre>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('```a\n```')), [['<pre class="code language-a" translate="no" data-lang="a"></pre>'], '']);
50
- assert.deepStrictEqual(inspect(parser('```A\n```')), [['<pre class="text" translate="no" data-path="A"></pre>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('```A\n```')), [['<pre class="code language-a" translate="no" data-lang="a"></pre>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser('```a-b\n```')), [['<pre class="code language-a-b" translate="no" data-lang="a-b"></pre>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser('```a-b0\n```')), [['<pre class="code language-a-b0" translate="no" data-lang="a-b0"></pre>'], '']);
53
53
  assert.deepStrictEqual(inspect(parser('```a--b\n```')), [['<pre class="text" translate="no" data-path="a--b"></pre>'], '']);
@@ -62,7 +62,10 @@ describe('Unit: parser/block/codeblock', () => {
62
62
  assert.deepStrictEqual(inspect(parser('```.b\n```')), [['<pre class="text" translate="no" data-path=".b"></pre>'], '']);
63
63
  assert.deepStrictEqual(inspect(parser('```b.c\n```')), [['<pre class="code language-c" translate="no" data-lang="c" data-path="b.c"></pre>'], '']);
64
64
  assert.deepStrictEqual(inspect(parser('```a b.c\n```')), [['<pre class="code language-a" translate="no" data-lang="a" data-path="b.c"></pre>'], '']);
65
- assert.deepStrictEqual(inspect(parser('```A b.c\n```')), [['<pre class="invalid" translate="no">```A b.c\n```</pre>'], '']);
65
+ assert.deepStrictEqual(inspect(parser('```a 1\n```')), [['<pre class="code language-a" translate="no" data-lang="a" data-line="1"></pre>'], '']);
66
+ assert.deepStrictEqual(inspect(parser('``` 1\n```')), [['<pre class="text" translate="no" data-line="1"></pre>'], '']);
67
+ assert.deepStrictEqual(inspect(parser('``` 1,2-3\n```')), [['<pre class="text" translate="no" data-line="1,2-3"></pre>'], '']);
68
+ assert.deepStrictEqual(inspect(parser('``` 1 b.c\n```')), [['<pre class="code language-c" translate="no" data-lang="c" data-line="1" data-path="b.c"></pre>'], '']);
66
69
  });
67
70
 
68
71
  });
@@ -3,12 +3,10 @@ import { CodeBlockParser } from '../block';
3
3
  import { eval } from '../../combinator/data/parser';
4
4
  import { some, block, validate, fence, clear, fmap } from '../../combinator';
5
5
  import { autolink } from '../autolink';
6
- import { escsource } from '../source';
7
6
  import { html, defrag } from 'typed-dom';
8
- import { join } from 'spica/array';
9
7
 
10
- const opener = /^(`{3,})(?!`)(\S*)([^\n]*)(?:$|\n)/;
11
- const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/;
8
+ const opener = /^(`{3,})(?!`)([^\n]*)(?:$|\n)/;
9
+ const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/i;
12
10
 
13
11
  export const segment: CodeBlockParser.SegmentParser = block(validate('```',
14
12
  clear(fence(opener, 300))));
@@ -19,35 +17,55 @@ export const segment_: CodeBlockParser.SegmentParser = block(validate('```',
19
17
  export const codeblock: CodeBlockParser = block(validate('```', fmap(
20
18
  fence(opener, 300),
21
19
  // Bug: Type mismatch between outer and inner.
22
- ([body, closer, opener, delim, lang, param]: string[], _, context) => {
23
- [lang, param] = language.test(lang)
24
- ? [lang, param]
25
- : ['', lang + param];
26
- param = param.trim();
27
- const path = join(eval(some(escsource, /^\s/)(param, context), []));
28
- if (!closer || param !== path) return [html('pre', {
20
+ ([body, closer, opener, delim, param]: string[], _, context) => {
21
+ const params = param.match(/(?:\\.?|\S)+/g)?.reduce<{
22
+ lang?: string;
23
+ path?: string;
24
+ line?: string;
25
+ invalid?: string;
26
+ }>((params, value, i) => {
27
+ let name: string;
28
+ switch (true) {
29
+ case i === 0
30
+ && value[0] === param[0]
31
+ && language.test(value):
32
+ name = 'lang';
33
+ value = value.toLowerCase();
34
+ break;
35
+ case /^\d+(?:[,-]\d+)*$/.test(value):
36
+ name = 'line';
37
+ break;
38
+ default:
39
+ name = 'path';
40
+ if (!params.lang) {
41
+ const file = value.split('/').pop() ?? '';
42
+ params.lang = file && file.includes('.', 1)
43
+ ? file.split('.').pop()?.match(language)?.[0].toLowerCase()
44
+ : params.lang;
45
+ }
46
+ }
47
+ name in params
48
+ ? params.invalid = `Duplicate ${name} value`
49
+ : params[name] = value;
50
+ return params;
51
+ }, {}) ?? {};
52
+ if (!closer || params.invalid) return [html('pre', {
29
53
  class: 'invalid',
30
54
  translate: 'no',
31
55
  'data-invalid-syntax': 'codeblock',
32
- 'data-invalid-type': !closer ? 'closer' : 'argument',
33
- 'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : 'Invalid argument',
56
+ 'data-invalid-type': !closer ? 'fence' : 'argument',
57
+ 'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : params.invalid,
34
58
  }, `${opener}${body}${closer}`)];
35
- const file = path.split('/').pop() ?? '';
36
- const ext = file && file.includes('.', 1)
37
- ? file.split('.').pop()!
38
- : '';
39
- lang = language.test(lang || ext)
40
- ? lang || ext
41
- : lang && 'invalid';
42
59
  const el = html('pre',
43
60
  {
44
- class: lang ? `code language-${lang}` : 'text',
61
+ class: params.lang ? `code language-${params.lang}` : 'text',
45
62
  translate: 'no',
46
- 'data-lang': lang || undefined,
47
- 'data-path': path || undefined,
63
+ 'data-lang': params.lang || undefined,
64
+ 'data-line': params.line || undefined,
65
+ 'data-path': params.path || undefined,
48
66
  },
49
- lang
50
- ? context.caches?.code?.get(`${lang}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes ||
67
+ params.lang
68
+ ? context.caches?.code?.get(`${params.lang ?? ''}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes ||
51
69
  body.slice(0, -1) || undefined
52
70
  : defrag(eval(some(autolink)(body.slice(0, -1), context), [])));
53
71
  return [el];
@@ -1,8 +1,6 @@
1
1
  import { DListParser } from '../block';
2
2
  import { union, inits, some, block, line, validate, rewrite, context, creator, open, trim, lazy, fmap } from '../../combinator';
3
- import { inline } from '../inline';
4
- import { indexer } from '../inline/extension/indexer';
5
- import { indexee } from '../inline/extension/indexee';
3
+ import { inline, indexee, indexer } from '../inline';
6
4
  import { anyline } from '../source';
7
5
  import { localize } from '../locale';
8
6
  import { visualize } from '../util';
@@ -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><blockquote></blockquote></div><figcaption><span class="figindex">Fig. 1.1. </span></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-type="quote" 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
  });
@@ -12,7 +12,7 @@ export const aside: ExtensionParser.AsideParser = creator(100, block(validate('~
12
12
  class: 'invalid',
13
13
  translate: 'no',
14
14
  'data-invalid-syntax': 'aside',
15
- 'data-invalid-type': !closer ? 'closer' : 'argument',
15
+ 'data-invalid-type': !closer ? 'fence' : 'argument',
16
16
  'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : 'Invalid argument',
17
17
  }, `${opener}${body}${closer}`)];
18
18
  const annotations = html('ol', { class: 'annotations' });
@@ -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><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>'], '']);
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-type="media" 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-type="media" 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>'], '']);
@@ -15,7 +15,7 @@ export const example: ExtensionParser.ExampleParser = creator(100, block(validat
15
15
  class: 'invalid',
16
16
  translate: 'no',
17
17
  'data-invalid-syntax': 'example',
18
- 'data-invalid-type': !closer ? 'closer' : 'argument',
18
+ 'data-invalid-type': !closer ? 'fence' : 'argument',
19
19
  'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : 'Invalid argument',
20
20
  }, `${opener}${body}${closer}`)];
21
21
  switch (type) {