@thi.ng/hiccup-markdown 3.0.1 → 3.1.0

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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-03-02T18:09:03Z
3
+ - **Last updated**: 2023-03-05T16:02:40Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,16 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [3.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/hiccup-markdown@3.1.0) (2023-03-05)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add anchor ID syntax support for headings ([86ce79e](https://github.com/thi-ng/umbrella/commit/86ce79e))
17
+ - update parse grammar & hd parser
18
+ - support for `{#id}` suffixes for defining heading anchor IDs
19
+ - only auto-generate anchor IDs if not explicitly specified
20
+ - update tests
21
+
12
22
  # [3.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/hiccup-markdown@3.0.0) (2023-02-27)
13
23
 
14
24
  #### 🛑 Breaking changes
package/README.md CHANGED
@@ -17,6 +17,7 @@ This project is part of the
17
17
  - [Code block headers](#code-block-headers)
18
18
  - [Custom blocks](#custom-blocks)
19
19
  - [Headings with anchor IDs](#headings-with-anchor-ids)
20
+ - [Heading with anchor {#custom-id-123}](#heading-with-anchor-custom-id-123)
20
21
  - [Metadata](#metadata)
21
22
  - [Customizing tag transforms](#customizing-tag-transforms)
22
23
  - [Serializing to HTML](#serializing-to-html)
@@ -58,7 +59,7 @@ standard syntax.
58
59
  | Code blocks | GFM style only (triple backtick prefix), w/ mandatory language hint & optional extra headers information |
59
60
  | Formatting | Nestable **bold**, _italic_, `code`, ~~strike~~, <kbd>Key</kbd> supported in paragraphs, headings, link labels, lists, blockquotes, tables |
60
61
  | Footnotes | Supported and stored separately in parse context |
61
- | Headings | ATX-style only (`#` line prefix), any level |
62
+ | Headings | ATX-style only (`#` line prefix), optional custom ID attrib (via `{#custom-id}` suffix), levels 1-6 then fallback to paragraph |
62
63
  | Horiz. Rulers | Only dash supported (e.g. `---`), min 2 chars required, length retained for downstream transformations |
63
64
  | HTML elements | Unsupported |
64
65
  | Images | Alt text is required, image can be used in link labels |
@@ -132,23 +133,30 @@ custom blocks (in an extensible manner).
132
133
 
133
134
  #### Headings with anchor IDs
134
135
 
135
- The default tag transform for headlines auto-generates ID attributes using that
136
- headline's body and
137
- [slugifying](https://docs.thi.ng/umbrella/strings/functions/slugifyGH.html) it
138
- (Github readme compatible):
136
+ The parser supports `{#custom-id}`-style line suffixes for headings, which are
137
+ passed as separate `anchorID` param to the element handlers. If not specified in
138
+ the Markdown source, the parser auto-generates this ID (with no uniqueness
139
+ guarantee) based on
140
+ [slugifying](https://docs.thi.ng/umbrella/strings/functions/slugifyGH.html) the
141
+ heading's body content (Github readme compatible):
139
142
 
140
143
  ```text
141
144
  # The **beautiful `code`**
145
+
146
+ ## Heading with anchor {#custom-id-123}
142
147
  ```
143
148
 
144
149
  Results in:
145
150
 
146
151
  ```js
147
152
  // [
148
- // "h1",
149
- // { id: "the-beautiful-code" },
150
- // "The ",
151
- // [ "strong", {}, "beautiful ", [ "code", {}, "code" ] ]
153
+ // [
154
+ // "h1",
155
+ // { id: "the-beautiful-code" },
156
+ // "The ",
157
+ // [ "strong", {}, "beautiful ", [ "code", {}, "code" ] ]
158
+ // ],
159
+ // [ "h2", { id: "custom-id-123" }, "Heading with anchor" ]
152
160
  // ]
153
161
  ```
154
162
 
@@ -462,7 +470,7 @@ For Node.js REPL:
462
470
  const hiccupMarkdown = await import("@thi.ng/hiccup-markdown");
463
471
  ```
464
472
 
465
- Package sizes (brotli'd, pre-treeshake): ESM: 4.35 KB
473
+ Package sizes (brotli'd, pre-treeshake): ESM: 4.42 KB
466
474
 
467
475
  ## Dependencies
468
476
 
package/api.d.ts CHANGED
@@ -110,11 +110,11 @@ export interface TagTransforms {
110
110
  *
111
111
  * @param ctx
112
112
  * @param level
113
- * @param id
113
+ * @param anchorID
114
114
  * @param body
115
115
  * @param meta
116
116
  */
117
- heading(ctx: TransformCtx, level: number, id: string, body: any[], meta?: any): any;
117
+ heading(ctx: TransformCtx, level: number, anchorID: string, body: any[], meta?: any): any;
118
118
  /**
119
119
  * Horizontal rule handler. Also receives number of dashes used (e.g. to
120
120
  * create different representations/styling)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/hiccup-markdown",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Markdown parser & serializer from/to Hiccup format",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -35,16 +35,16 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@thi.ng/api": "^8.7.3",
38
- "@thi.ng/arrays": "^2.5.6",
38
+ "@thi.ng/arrays": "^2.5.7",
39
39
  "@thi.ng/checks": "^3.3.9",
40
40
  "@thi.ng/defmulti": "^2.1.31",
41
41
  "@thi.ng/emoji": "^0.1.0",
42
42
  "@thi.ng/errors": "^2.2.12",
43
- "@thi.ng/hiccup": "^4.2.34",
43
+ "@thi.ng/hiccup": "^4.2.35",
44
44
  "@thi.ng/logger": "^1.4.9",
45
45
  "@thi.ng/parse": "^2.2.28",
46
46
  "@thi.ng/strings": "^3.4.1",
47
- "@thi.ng/text-canvas": "^2.4.31"
47
+ "@thi.ng/text-canvas": "^2.4.32"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@microsoft/api-extractor": "^7.34.2",
@@ -95,5 +95,5 @@
95
95
  "parent": "@thi.ng/hiccup",
96
96
  "year": 2018
97
97
  },
98
- "gitHead": "a2915dee637c1b8cd2e11a78a23bd035e4f750e7\n"
98
+ "gitHead": "8342900eedc77bb09edb8c544804578b71f8acc6\n"
99
99
  }
package/parse.js CHANGED
@@ -1,5 +1,5 @@
1
- // Downloaded @ 2023-02-26T13:59:47.034Z
2
- // Source: https://demo.thi.ng/umbrella/parse-playground/#ldoNR0ROTDE6IDxETkw-KyA9PiBkaXNjYXJkIDsKRE5MMjogPE5MPnsyLH0gOwpsYnI6ICdcXCchIDxOTD4hIDsKZXNjOiAnXFwnISAoICc8JyB8ICdbJyB8ICdfJyB8ICcqJyB8ICdgJyB8ICd-JyB8ICc6JyApIDsKaW5saW5lZGVsaW06ICggIiFbIiB8ICdbJyB8ICIqKiIgfCAnXycgfCAnYCcgfCAnPCcgfCAnXFwnIHwgIn5-IiB8ICIgOiIgfCA8bGJyPiApIDsKZGVsaW06ICggPGlubGluZWRlbGltPiB8IDxETkwyPiApIDsKZGVsaW0xOiAoIDxpbmxpbmVkZWxpbT4gfCA8Tkw-ICkgOwpib2R5OiAuKD8tPGRlbGltPiEpID0-IGpvaW4gOwpib2R5MTogLig_LTxkZWxpbTE-ISkgPT4gam9pbiA7Cgp3aWtpcmVmOiAiW1siISAuKD8rIl1dIiEpID0-IGpvaW4gOwpmbnJlZjogIlteIiEgPGxhYmVsPiA7CmZub3RlOiA8TFNUQVJUPiAiW14iISA8Zm5sYWJlbD4gPFdTMT4gPHBhcmE-IDsKZm5sYWJlbDogLig_KyJdOiIhKSA9PiBqb2luIDsKbGFiZWw6IC4oPysnXSchKSA9PiBqb2luIDsKdGFyZ2V0OiAuKD8rJyknISkgPT4gam9pbiA7Cmxpbms6ICdbJyEgPGxpbmtsYWJlbD4gJygnISA8dGFyZ2V0PiA7CmxpbmtyZWY6ICdbJyEgPGxpbmtsYWJlbD4gJ1snISA8bGFiZWw-IDsKbGlua2RlZjogPExTVEFSVD4gJ1snISA8bGFiZWw-ICc6JyEgPFdTMT4gPGxkdGFyZ2V0PiA7CmxkdGFyZ2V0OiAuKD8rPEROTDE-KSA9PiBqb2luIDsKbGlua2xhYmVsOiAoPGltZz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxsaW5rYm9keT4pKiAnXSchIDsKbGlua2RlbGltOiAoICIhWyIgfCAnWycgfCAiKioiIHwgJ18nIHwgIn5-IiB8ICdgJyB8ICddJykgOwpsaW5rYm9keTogLig_LTxsaW5rZGVsaW0-ISkgPT4gam9pbiA7CmltZzogIiFbIiEgPGxhYmVsPiAnKCchIDx0YXJnZXQ-IDsKYm9sZDogIioqIiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJvZHkxPikqICIqKiIhIDsKaXRhbGljOiAnXychICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGlua3JlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8Ym9keTE-KSogJ18nISA7CnN0cmlrZTogIn5-IiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxib2R5MT4pKiAifn4iISA7CmNvZGU6ICdgJyEgLig_KydgJyEpID0-IGpvaW4gOwprYmQ6ICI8a2JkPiIhIC4oPysiPC9rYmQ-IiEpID0-IGpvaW4gOwplbW9qaTogJyAnPyAnOichICg8QUxQSEFfTlVNPiB8ICcrJyB8ICctJykoPysnOichKSA9PiBqb2luIDsKcGFyYTogKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8a2JkPiB8IDxlbW9qaT4gfCA8bGJyPiB8IDxlc2M-IHwgPGJvZHk-KSogPEROTDI-ISA7CgpoZGxldmVsOiAnIycrID0-IGNvdW50IDsKaGQ6IDxMU1RBUlQ-IDxoZGxldmVsPiA8V1MwPgogICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJvZHkxPiApKiA8RE5MMT4gOwoKbGlsZXZlbDogJyAnKiA9PiBjb3VudCA7CnVpbnQ6IDxESUdJVD4rID0-IGludCA7CnVsaWQ6IDxETkw-IDxXUzA-ICctJyEgOwpvbGlkOiA8RE5MPiA8V1MwPiA8RElHSVQ-KyEgJy4nISA7CmxpZGVsaW06ICggPGRlbGltPiB8IDx1bGlkPiB8IDxvbGlkPiApIDsKbGlib2R5OiAuKD8tPGxpZGVsaW0-ISkgPT4gam9pbiA7CnRvZG86ICdbJyEgWyB4WF0gJ10nISA8V1MxPiA9PiBob2lzdFIgOwp1bGl0ZW06IDxMU1RBUlQ-IDxsaWxldmVsPiAiLSAiISA8dG9kbz4_CiAgICAgICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGxpYm9keT4gKSogPEROTD4gOwpvbGl0ZW06IDxMU1RBUlQ-IDxsaWxldmVsPiA8dWludD4gIi4gIiEgPHRvZG8-PwogICAgICAgICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxsaWJvZHk-ICkqIDxETkw-IDsKbGlzdDogKDx1bGl0ZW0-IHwgPG9saXRlbT4pKyA8RE5MMT4gOwoKY2JkZWxpbTogPExTVEFSVD4gImBgYCIhIDsKY29kZWJsb2NrOiA8Y2JkZWxpbT4hIDxjb2RlbWV0YT4gPGNvZGVib2R5PiA8RE5MMT4gOwpjb2RlbWV0YTogLig_KzxOTD4hKSA9PiBqb2luIDsKY29kZWJvZHk6IC4oPys8Y2JkZWxpbT4pID0-IGpvaW4gOwoKY3VzdG9tZGVsaW06IDxMU1RBUlQ-ICI6OjoiISA7CmN1c3RvbWJsb2NrOiA8Y3VzdG9tZGVsaW0-ISA8Y3VzdG9tbWV0YT4gPGN1c3RvbWJvZHk-IDxETkwxPiA7CmN1c3RvbW1ldGE6IC4oPys8Tkw-ISkgPT4gam9pbiA7CmN1c3RvbWJvZHk6IC4oPys8Y3VzdG9tZGVsaW0-KSA9PiBqb2luIDsKCm1ldGFibG9jazogPExTVEFSVD4gInt7eyIhIDxtZXRhYm9keT4gPEROTDE-IDsKbWV0YWJvZHk6IC4oPys8bWV0YWVuZD4hKSA9PiBqb2luIDsKbWV0YWVuZDogIn19fSIgPExFTkQ-IDsKCmJxbGV2ZWw6ICc-JysgPT4gY291bnQgOwpicWxpbmU6IDxMU1RBUlQ-IDxicWxldmVsPiAnICc_IQogICAgICAgICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxicWxicj4gfCA8Ym9keTE-KSogPEROTD4gOwpicWxicjogJ1xcJyEoPy08RE5MPikgOwpicXVvdGU6IDxicWxpbmU-KyA8RE5MMT4gOwoKdGRlbGltOiAoPGlubGluZWRlbGltPiB8ICd8JyApIDsKdGJvZHk6IC4oPy08dGRlbGltPiEpID0-IGpvaW4gOwp0Y2VsbDogPFdTMD4gKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPHRib2R5PiApKiAnfCchIDsKdHJvdzogPExTVEFSVD4gJ3wnISA8dGNlbGw-KD8rPEROTD4pIDsKdGFibGU6IDx0cm93PisgPEROTDE-IDsKCmhyOiAiLS0iICctJysgPEROTDE-ID0-IGpvaW4gOwoKbWFpbjogPFdTMD4gKDxoZD4gfCA8bGlzdD4gfCA8YnF1b3RlPiB8IDxjb2RlYmxvY2s-IHwgPGN1c3RvbWJsb2NrPiB8IDxtZXRhYmxvY2s-IHwgPHRhYmxlPiB8IDxocj4gfCA8Zm5vdGU-IHwgPGxpbmtkZWY-IHwgPHBhcmE-KSogO6RtYWlu2gKLIyBIZWxsbyA6d29ybGQ6OnNtaWxlOlteYWJjXQoKYSBcPCBiCgpMZXQgYGV4cDIoeCkgPSAyKip4YAoKUHJlc3MgPGtiZD5Db250cm9sPC9rYmQ-ICsgPGtiZD5SPC9rYmQ-IHRvIHJlbG9hZC4KCjo6OmFsZXJ0ClRlc3QgW2xhYmVsXVtyZWZyZWZdCjo6OgoKLS0tCgp7e3sgeyJpZCI6IDEyMywgInByb3RlY3RlZCI6IHRydWUgfSB9fX0KU28gW1tzbWlsZV9mb28xMl1dIPCfmI0gd2hhdCdzIFt0aGlzXSguL3RoaXMubWQpW14yXSB0aGVuOgoKQSBbbGluayBfd2l0aCAqKm5lc3RlZCB-fmZvcm1hdH5-KiogYW5kIGByZWZlcmVuY2VgX11bcmVmcmVmXS4uLgoKYGBgdHMgdGFuZ2xlOm5vIGxuOnllcwpjb25zdCBmb28gPSA0MjsKLy8gdGhlIGVuZApgYGAKCjEuIGZvbwogIDQuIGJhcgogICAgIGJheiBhbmQgc28gb24KICAgICBtdWx0aWxpbmUKMi4gWyBdIHRhc2sKMy4gW3hdICoqZG9uZSoqCgo-IGJsb2NrcXVvdGUKPiBtdWx0aWxpbmUgdG9vXAo-PiBuZXN0ZWQKPj4-IGxldmVsIDMKPiAtLSBzb3VyY2UKCnwgZm9vIHwgYmFyIHwKfDotfC06fAp8IFtbcmVmIzIyXV0gfCBgb25gICoqb2ZmKiogfAoKW15hYmNdOiBGb28gX2Jhcl8gYmF6CgpbXjJdOiBUT0RPCgpbcmVmcmVmXTogaHR0cDovL3RoaS5uZy8KW2Zvb106IC4vZm9vLm1kI2JhcgoK2TUxMS4gYWJjCiAgLSB4eXoKMjEuIHh4eAogIDEuIGZvbwogICAgMS4gYmFyCjMxLiB5eXkKCtlWPiAqKmxldmVsIDFhKioKPj4gbGV2ZWwgMmEKPj4gbGV2ZWwgMmIKPgo-IGxldmVsIDFiCgpbKipmb28qKl0oYmFyKQoKKiohW2Zvb10oYmFyKSoqCgo
1
+ // Downloaded @ 2023-03-05T09:08:51.082Z
2
+ // Source: https://demo.thi.ng/umbrella/parse-playground/#ldoNwUROTDE6IDxETkw-KyA9PiBkaXNjYXJkIDsKRE5MMjogPE5MPnsyLH0gOwpsYnI6ICdcXCchIDxOTD4hIDsKZXNjOiAnXFwnISAoICc8JyB8ICdbJyB8ICdfJyB8ICcqJyB8ICdgJyB8ICd-JyB8ICc6JyApIDsKaW5saW5lZGVsaW06ICggIiFbIiB8ICdbJyB8ICIqKiIgfCAnXycgfCAnYCcgfCAnPCcgfCAnXFwnIHwgIn5-IiB8ICIgOiIgfCA8bGJyPiApIDsKZGVsaW06ICggPGlubGluZWRlbGltPiB8IDxETkwyPiApIDsKZGVsaW0xOiAoIDxpbmxpbmVkZWxpbT4gfCA8Tkw-ICkgOwpib2R5OiAuKD8tPGRlbGltPiEpID0-IGpvaW4gOwpib2R5MTogLig_LTxkZWxpbTE-ISkgPT4gam9pbiA7Cgp3aWtpcmVmOiAiW1siISAuKD8rIl1dIiEpID0-IGpvaW4gOwpmbnJlZjogIlteIiEgPGxhYmVsPiA7CmZub3RlOiA8TFNUQVJUPiAiW14iISA8Zm5sYWJlbD4gPFdTMT4gPHBhcmE-IDsKZm5sYWJlbDogLig_KyJdOiIhKSA9PiBqb2luIDsKbGFiZWw6IC4oPysnXSchKSA9PiBqb2luIDsKdGFyZ2V0OiAuKD8rJyknISkgPT4gam9pbiA7Cmxpbms6ICdbJyEgPGxpbmtsYWJlbD4gJygnISA8dGFyZ2V0PiA7CmxpbmtyZWY6ICdbJyEgPGxpbmtsYWJlbD4gJ1snISA8bGFiZWw-IDsKbGlua2RlZjogPExTVEFSVD4gJ1snISA8bGFiZWw-ICc6JyEgPFdTMT4gPGxkdGFyZ2V0PiA7CmxkdGFyZ2V0OiAuKD8rPEROTDE-KSA9PiBqb2luIDsKbGlua2xhYmVsOiAoPGltZz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxsaW5rYm9keT4pKiAnXSchIDsKbGlua2RlbGltOiAoICIhWyIgfCAnWycgfCAiKioiIHwgJ18nIHwgIn5-IiB8ICdgJyB8ICddJykgOwpsaW5rYm9keTogLig_LTxsaW5rZGVsaW0-ISkgPT4gam9pbiA7CmltZzogIiFbIiEgPGxhYmVsPiAnKCchIDx0YXJnZXQ-IDsKYm9sZDogIioqIiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJvZHkxPikqICIqKiIhIDsKaXRhbGljOiAnXychICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGlua3JlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8Ym9keTE-KSogJ18nISA7CnN0cmlrZTogIn5-IiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxib2R5MT4pKiAifn4iISA7CmNvZGU6ICdgJyEgLig_KydgJyEpID0-IGpvaW4gOwprYmQ6ICI8a2JkPiIhIC4oPysiPC9rYmQ-IiEpID0-IGpvaW4gOwplbW9qaTogJyAnPyAnOichICg8QUxQSEFfTlVNPiB8ICcrJyB8ICctJykoPysnOichKSA9PiBqb2luIDsKcGFyYTogKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8a2JkPiB8IDxlbW9qaT4gfCA8bGJyPiB8IDxlc2M-IHwgPGJvZHk-KSogPEROTDI-ISA7CgpoZGxldmVsOiAnIycrID0-IGNvdW50IDsKaGRpZDogInsjIiEgKDxBTFBIQV9OVU0-IHwgJy0nKSsgJ30nISA9PiBqb2luIDsKaGRkZWxpbTogKCA8ZGVsaW0xPiB8ICJ7IyIgKSA7CmhkYm9keTogLig_LTxoZGRlbGltPiEpID0-IGpvaW4gOwpoZDogPExTVEFSVD4gPGhkbGV2ZWw-IDxXUzA-CiAgICAoPHdpa2lyZWY-IHwgPGltZz4gfCA8Zm5yZWY-IHwgPGxpbms-IHwgPGJvbGQ-IHwgPGl0YWxpYz4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8aGRib2R5PiApKiA8aGRpZD4_IDxETkwxPiA7CgpsaWxldmVsOiAnICcqID0-IGNvdW50IDsKdWludDogPERJR0lUPisgPT4gaW50IDsKdWxpZDogPEROTD4gPFdTMD4gJy0nISA7Cm9saWQ6IDxETkw-IDxXUzA-IDxESUdJVD4rISAnLichIDsKbGlkZWxpbTogKCA8ZGVsaW0-IHwgPHVsaWQ-IHwgPG9saWQ-ICkgOwpsaWJvZHk6IC4oPy08bGlkZWxpbT4hKSA9PiBqb2luIDsKdG9kbzogJ1snISBbIHhYXSAnXSchIDxXUzE-ID0-IGhvaXN0UiA7CnVsaXRlbTogPExTVEFSVD4gPGxpbGV2ZWw-ICItICIhIDx0b2RvPj8KICAgICAgICAoPHdpa2lyZWY-IHwgPGltZz4gfCA8Zm5yZWY-IHwgPGxpbms-IHwgPGJvbGQ-IHwgPGl0YWxpYz4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8bGlib2R5PiApKiA8RE5MPiA7Cm9saXRlbTogPExTVEFSVD4gPGxpbGV2ZWw-IDx1aW50PiAiLiAiISA8dG9kbz4_CiAgICAgICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGxpYm9keT4gKSogPEROTD4gOwpsaXN0OiAoPHVsaXRlbT4gfCA8b2xpdGVtPikrIDxETkwxPiA7CgpjYmRlbGltOiA8TFNUQVJUPiAiYGBgIiEgOwpjb2RlYmxvY2s6IDxjYmRlbGltPiEgPGNvZGVtZXRhPiA8Y29kZWJvZHk-IDxETkwxPiA7CmNvZGVtZXRhOiAuKD8rPE5MPiEpID0-IGpvaW4gOwpjb2RlYm9keTogLig_KzxjYmRlbGltPikgPT4gam9pbiA7CgpjdXN0b21kZWxpbTogPExTVEFSVD4gIjo6OiIhIDsKY3VzdG9tYmxvY2s6IDxjdXN0b21kZWxpbT4hIDxjdXN0b21tZXRhPiA8Y3VzdG9tYm9keT4gPEROTDE-IDsKY3VzdG9tbWV0YTogLig_KzxOTD4hKSA9PiBqb2luIDsKY3VzdG9tYm9keTogLig_KzxjdXN0b21kZWxpbT4pID0-IGpvaW4gOwoKbWV0YWJsb2NrOiA8TFNUQVJUPiAie3t7IiEgPG1ldGFib2R5PiA8RE5MMT4gOwptZXRhYm9keTogLig_KzxtZXRhZW5kPiEpID0-IGpvaW4gOwptZXRhZW5kOiAifX19IiA8TEVORD4gOwoKYnFsZXZlbDogJz4nKyA9PiBjb3VudCA7CmJxbGluZTogPExTVEFSVD4gPGJxbGV2ZWw-ICcgJz8hCiAgICAgICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJxbGJyPiB8IDxib2R5MT4pKiA8RE5MPiA7CmJxbGJyOiAnXFwnISg_LTxETkw-KSA7CmJxdW90ZTogPGJxbGluZT4rIDxETkwxPiA7Cgp0ZGVsaW06ICg8aW5saW5lZGVsaW0-IHwgJ3wnICkgOwp0Ym9keTogLig_LTx0ZGVsaW0-ISkgPT4gam9pbiA7CnRjZWxsOiA8V1MwPiAoPHdpa2lyZWY-IHwgPGltZz4gfCA8Zm5yZWY-IHwgPGxpbms-IHwgPGJvbGQ-IHwgPGl0YWxpYz4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8dGJvZHk-ICkqICd8JyEgOwp0cm93OiA8TFNUQVJUPiAnfCchIDx0Y2VsbD4oPys8RE5MPikgOwp0YWJsZTogPHRyb3c-KyA8RE5MMT4gOwoKaHI6ICItLSIgJy0nKyA8RE5MMT4gPT4gam9pbiA7CgptYWluOiA8V1MwPiAoPGhkPiB8IDxsaXN0PiB8IDxicXVvdGU-IHwgPGNvZGVibG9jaz4gfCA8Y3VzdG9tYmxvY2s-IHwgPG1ldGFibG9jaz4gfCA8dGFibGU-IHwgPGhyPiB8IDxmbm90ZT4gfCA8bGlua2RlZj4gfCA8cGFyYT4pKiA7pG1haW7aAqgjIEhlbGxvIDp3b3JsZDo6c21pbGU6W15hYmNdIHsjaGQxfQoKIyMgYWJjIHsjaGQyfQojIyBkZWYKCmEgXDwgYgoKTGV0IGBleHAyKHgpID0gMioqeGAKClByZXNzIDxrYmQ-Q29udHJvbDwva2JkPiArIDxrYmQ-Ujwva2JkPiB0byByZWxvYWQuCgo6OjphbGVydApUZXN0IFtsYWJlbF1bcmVmcmVmXQo6OjoKCi0tLQoKe3t7IHsiaWQiOiAxMjMsICJwcm90ZWN0ZWQiOiB0cnVlIH0gfX19ClNvIFtbc21pbGVfZm9vMTJdXSDwn5iNIHdoYXQncyBbdGhpc10oLi90aGlzLm1kKVteMl0gdGhlbjoKCkEgW2xpbmsgX3dpdGggKipuZXN0ZWQgfn5mb3JtYXR-fioqIGFuZCBgcmVmZXJlbmNlYF9dW3JlZnJlZl0uLi4KCmBgYHRzIHRhbmdsZTpubyBsbjp5ZXMKY29uc3QgZm9vID0gNDI7Ci8vIHRoZSBlbmQKYGBgCgoxLiBmb28KICA0LiBiYXIKICAgICBiYXogYW5kIHNvIG9uCiAgICAgbXVsdGlsaW5lCjIuIFsgXSB0YXNrCjMuIFt4XSAqKmRvbmUqKgoKPiBibG9ja3F1b3RlCj4gbXVsdGlsaW5lIHRvb1wKPj4gbmVzdGVkCj4-PiBsZXZlbCAzCj4gLS0gc291cmNlCgp8IGZvbyB8IGJhciB8Cnw6LXwtOnwKfCBbW3JlZiMyMl1dIHwgYG9uYCAqKm9mZioqIHwKClteYWJjXTogRm9vIF9iYXJfIGJhegoKW14yXTogVE9ETwoKW3JlZnJlZl06IGh0dHA6Ly90aGkubmcvCltmb29dOiAuL2Zvby5tZCNiYXIKCtk1MTEuIGFiYwogIC0geHl6CjIxLiB4eHgKICAxLiBmb28KICAgIDEuIGJhcgozMS4geXl5CgrZVj4gKipsZXZlbCAxYSoqCj4-IGxldmVsIDJhCj4-IGxldmVsIDJiCj4KPiBsZXZlbCAxYgoKWyoqZm9vKipdKGJhcikKCioqIVtmb29dKGJhcikqKgoK
3
3
  import { peek } from "@thi.ng/arrays/peek";
4
4
  import { isArray } from "@thi.ng/checks/is-array";
5
5
  import { isPlainObject } from "@thi.ng/checks/is-plain-object";
@@ -45,8 +45,11 @@ emoji: ' '? ':'! (<ALPHA_NUM> | '+' | '-')(?+':'!) => join ;
45
45
  para: (<wikiref> | <img> | <fnref> | <linkref> | <link> | <bold> | <italic> | <strike> | <code> | <kbd> | <emoji> | <lbr> | <esc> | <body>)* <DNL2>! ;
46
46
 
47
47
  hdlevel: '#'+ => count ;
48
+ hdid: "{#"! (<ALPHA_NUM> | '-')+ '}'! => join ;
49
+ hddelim: ( <delim1> | "{#" ) ;
50
+ hdbody: .(?-<hddelim>!) => join ;
48
51
  hd: <LSTART> <hdlevel> <WS0>
49
- (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <body1> )* <DNL1> ;
52
+ (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <hdbody> )* <hdid>? <DNL1> ;
50
53
 
51
54
  lilevel: ' '* => count ;
52
55
  uint: <DIGIT>+ => int ;
@@ -259,6 +262,7 @@ export const transformScope = defmulti((x, ctx) => {
259
262
  body1: "body",
260
263
  bqlbr: "lbr",
261
264
  bqline: "repeat0",
265
+ hdbody: "body",
262
266
  label: "body",
263
267
  libody: "body",
264
268
  linkbody: "body",
@@ -353,9 +357,10 @@ export const transformScope = defmulti((x, ctx) => {
353
357
  const body = [];
354
358
  const level = children[0].result;
355
359
  transformScope(children[1], ctx, body);
356
- ctx.headings.push({ level, body });
357
360
  __trimBody(body);
358
- __collect(acc, ctx.tags.heading(ctx, level, slugifyGH(extractBody(body).join("")), body, ctx.meta));
361
+ const slug = children[2]?.result || slugifyGH(extractBody(body).join(""));
362
+ ctx.headings.push({ level, body });
363
+ __collect(acc, ctx.tags.heading(ctx, level, slug, body, ctx.meta));
359
364
  ctx.meta = null;
360
365
  },
361
366
  hr: (scope, ctx, acc) => {