Skip to content

Commit b33a071

Browse files
authored
fix(jsx-ast): preserve generated footnotes (#797)
1 parent 79de8ae commit b33a071

2 files changed

Lines changed: 70 additions & 8 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import assert from 'node:assert/strict';
2+
import { describe, it } from 'node:test';
3+
4+
import transformer from '../transformer.mjs';
5+
6+
describe('jsx-ast transformer', () => {
7+
it('moves generated footnotes into the Layout children', () => {
8+
const layout = {
9+
type: 'mdxJsxTextElement',
10+
name: 'Layout',
11+
children: [{ type: 'element', tagName: 'p', children: [] }],
12+
};
13+
const footnotes = {
14+
type: 'element',
15+
tagName: 'section',
16+
properties: { dataFootnotes: '', className: ['footnotes'] },
17+
children: [
18+
{
19+
type: 'element',
20+
tagName: 'ol',
21+
children: [
22+
{
23+
type: 'element',
24+
tagName: 'li',
25+
properties: { id: 'user-content-fn-a' },
26+
children: [{ type: 'text', value: 'Footnote text' }],
27+
},
28+
],
29+
},
30+
],
31+
};
32+
const tree = {
33+
type: 'root',
34+
children: [layout, { type: 'text', value: '\n' }, footnotes],
35+
};
36+
37+
transformer()(tree);
38+
39+
assert.equal(tree.children.includes(footnotes), false);
40+
assert.equal(layout.children.at(-1), footnotes);
41+
});
42+
});

src/generators/jsx-ast/utils/transformer.mjs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,23 @@ import { visit } from 'unist-util-visit';
33

44
import { TAG_TRANSFORMS } from '../constants.mjs';
55

6+
/**
7+
* Checks whether a HAST node is the generated GFM footnotes section.
8+
* @param {import('hast').Element} node
9+
*/
10+
const isFootnotesSection = node =>
11+
node?.type === 'element' &&
12+
node.tagName === 'section' &&
13+
(node.properties?.dataFootnotes !== undefined ||
14+
node.properties?.className?.includes('footnotes'));
15+
16+
/**
17+
* Finds the generated page Layout node.
18+
* @param {import('hast').Root} tree
19+
*/
20+
const findLayout = tree =>
21+
tree.children.find(node => node.name === 'Layout' && node.children);
22+
623
/**
724
* @template {import('unist').Node} T
825
* @param {T} tree
@@ -43,14 +60,17 @@ const transformer = tree => {
4360
}
4461
});
4562

46-
// Are there footnotes?
47-
if (tree.children.at(-1).tagName === 'section') {
48-
const section = tree.children.pop();
49-
// If so, move it into the proper location
50-
// Root -> Article -> Main content
51-
tree.children[2]?.children[1]?.children[0]?.children?.push(
52-
...section.children
53-
);
63+
const index = tree.children.findLastIndex(isFootnotesSection);
64+
65+
if (index !== -1) {
66+
const [section] = tree.children.splice(index, 1);
67+
const layout = findLayout(tree);
68+
69+
if (layout) {
70+
layout.children.push(section);
71+
} else {
72+
tree.children.push(section);
73+
}
5474
}
5575
};
5676

0 commit comments

Comments
 (0)