Skip to content

Commit 4dd2959

Browse files
authored
👌 IMPROVE: Add parsed_directive and parsed_role parent tokens (#34)
In order to not lose the information, of what nodes were generated from directives/roles, these nodes are now wrapped inside `parsed_directive` and `parsed_role` parent tokens, e.g. ```xml <admonition class="note" ...> ... ``` will now be output as: ```xml <parsed_directive name="note" ...> <admonition class="note" ...> ... ``` Additionally, `legend` tokens for paragraphs have been added, after `caption` in figure directives.
1 parent 4bc6023 commit 4dd2959

File tree

7 files changed

+60
-12
lines changed

7 files changed

+60
-12
lines changed

src/directives/images.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,11 @@ export class Figure extends Image {
121121
const imageToken = this.create_image(data)
122122
imageToken.map = [data.map[0], data.map[0]]
123123
let captionTokens: Token[] = []
124+
let legendTokens: Token[] = []
124125
if (data.body) {
126+
const [caption, ...legendParts] = data.body.split("\n\n")
127+
const legend = legendParts.join("\n\n")
128+
const captionMap = data.bodyMap[0]
125129
const openCaption = this.createToken("figure_caption_open", "figcaption", 1, {
126130
block: true
127131
})
@@ -130,14 +134,25 @@ export class Figure extends Image {
130134
}
131135
// TODO in docutils caption can only be single paragraph (or ignored if comment)
132136
// then additional content is figure legend
133-
const captionBody = this.nestedParse(data.body, data.bodyMap[0])
137+
const captionBody = this.nestedParse(caption, captionMap)
134138
const closeCaption = this.createToken("figure_caption_close", "figcaption", -1, {
135139
block: true
136140
})
137141
captionTokens = [openCaption, ...captionBody, closeCaption]
142+
if (legend) {
143+
const legendMap = captionMap + caption.split("\n").length + 1
144+
const openLegend = this.createToken("figure_legend_open", "", 1, {
145+
block: true
146+
})
147+
const legendBody = this.nestedParse(legend, legendMap)
148+
const closeLegend = this.createToken("figure_legend_close", "", -1, {
149+
block: true
150+
})
151+
legendTokens = [openLegend, ...legendBody, closeLegend]
152+
}
138153
}
139154
const closeToken = this.createToken("figure_close", "figure", -1, { block: true })
140-
return [openToken, imageToken, ...captionTokens, closeToken]
155+
return [openToken, imageToken, ...captionTokens, ...legendTokens, closeToken]
141156
}
142157
}
143158

src/directives/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export default function directiveToData(
213213
}
214214
}
215215

216-
function parseDirectiveOptions(
216+
export function parseDirectiveOptions(
217217
content: string[],
218218
fullSpec: IDirectiveSpec
219219
): [string[], { [key: string]: any }, number] {

src/directives/plugin.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type MarkdownIt from "markdown-it/lib"
22
import type StateCore from "markdown-it/lib/rules_core/state_core"
3-
import directiveToData, { Directive } from "./main"
3+
import directiveToData, { Directive, parseDirectiveOptions } from "./main"
44
import { IOptions } from "./types"
55

66
export default function directivePlugin(md: MarkdownIt, options: IOptions): void {
@@ -53,12 +53,28 @@ function runDirectives(directives: {
5353
try {
5454
const directive = new directives[token.info](state)
5555
const data = directiveToData(token, directive)
56-
const newTokens = directive.run(data)
57-
// Ensure `meta` exists and add the directive options
58-
newTokens[0].meta = {
56+
const [content, opts] = parseDirectiveOptions(
57+
token.content.trim() ? token.content.split(/\r?\n/) : [],
58+
directive
59+
)
60+
const directiveOpen = new state.Token("parsed_directive_open", "", 1)
61+
directiveOpen.info = token.info
62+
directiveOpen.hidden = true
63+
directiveOpen.content = content.join("\n").trim()
64+
directiveOpen.meta = {
65+
arg: token.meta.arg,
66+
opts
67+
}
68+
const newTokens = [directiveOpen]
69+
newTokens.push(...directive.run(data))
70+
const directiveClose = new state.Token("parsed_directive_close", "", -1)
71+
directiveClose.hidden = true
72+
newTokens.push(directiveClose)
73+
// Ensure `meta` exists and add the directive options to parsed child
74+
newTokens[1].meta = {
5975
directive: true,
6076
...data.options,
61-
...newTokens[0].meta
77+
...newTokens[1].meta
6278
}
6379
finalTokens.push(...newTokens)
6480
} catch (err) {

src/roles/plugin.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function roleRule(state: StateInline, silent: boolean): boolean {
5252
}
5353

5454
// MyST role syntax format e.g. {role}`text`
55+
// TODO: support role with no value e.g. {role}``
5556
let _x: RegExp
5657
try {
5758
_x = new RegExp("^\\{([a-zA-Z_\\-+:]{1,36})\\}(`+)(?!`)(.+?)(?<!`)\\2(?!`)")
@@ -75,10 +76,22 @@ function runRoles(roles: {
7576
if (child.type === "role" && child.meta?.name in roles) {
7677
try {
7778
const role = new roles[child.meta.name](state)
78-
const newTokens = role.run({
79-
parentMap: token.map,
80-
content: child.content
81-
})
79+
const roleOpen = new state.Token("parsed_role_open", "", 1)
80+
roleOpen.content = child.content
81+
roleOpen.hidden = true
82+
roleOpen.meta = { name: child.meta.name }
83+
roleOpen.block = false
84+
const newTokens = [roleOpen]
85+
newTokens.push(
86+
...role.run({
87+
parentMap: token.map,
88+
content: child.content
89+
})
90+
)
91+
const roleClose = new state.Token("parsed_role_close", "", -1)
92+
roleClose.block = false
93+
roleClose.hidden = true
94+
newTokens.push(roleClose)
8295
childTokens.push(...newTokens)
8396
} catch (err) {
8497
const errorToken = new state.Token("role_error", "", 0)

tests/fixtures/directives.admonitions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ nested-admonition
5757
<aside class="admonition note">
5858
<header class="admonition-title">Note</header>
5959
<p>This is a note</p>
60+
6061
<aside class="admonition warning">
6162
<header class="admonition-title">Warning</header>
6263
<p>This is a nested warning</p>

tests/fixtures/roles.references.eq.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ Check out {eq}`my_label`!
99
<div class="math block" id="my_label" number="1">
1010
w_{t+1} = (1 + r_{t+1}) s(w_t) + y_{t+1}
1111
</div>
12+
1213
<p>Check out <a href="#my_label">(1)</a>!</p>
1314
.

tests/fixtures/roles.references.numref.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ The reference to {ref}`test3` and {ref}`test4`.
3030
<p>Fig 1</p>
3131
</figcaption>
3232
</figure>
33+
3334
<figure id="test4" class="numbered">
3435
<img src="https://via.placeholder.com/150" alt="">
3536
<figcaption number="2">
3637
<p>Fig 2</p>
3738
</figcaption>
3839
</figure>
40+
3941
<p>The reference to <a href="#test3" title="Fig 1">Fig 1</a> and <a href="#test4" title="Fig 2">Fig 2</a>.
4042
<a href="#test3" title="Fig 1">Fig 1</a>
4143
<a href="#test4" title="Fig 2">Fig 2</a>

0 commit comments

Comments
 (0)