diff --git a/src/generators/jsx-ast/utils/__tests__/transformer.test.mjs b/src/generators/jsx-ast/utils/__tests__/transformer.test.mjs new file mode 100644 index 00000000..4b7df072 --- /dev/null +++ b/src/generators/jsx-ast/utils/__tests__/transformer.test.mjs @@ -0,0 +1,42 @@ +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; + +import transformer from '../transformer.mjs'; + +describe('jsx-ast transformer', () => { + it('moves generated footnotes into the Layout children', () => { + const layout = { + type: 'mdxJsxTextElement', + name: 'Layout', + children: [{ type: 'element', tagName: 'p', children: [] }], + }; + const footnotes = { + type: 'element', + tagName: 'section', + properties: { dataFootnotes: '', className: ['footnotes'] }, + children: [ + { + type: 'element', + tagName: 'ol', + children: [ + { + type: 'element', + tagName: 'li', + properties: { id: 'user-content-fn-a' }, + children: [{ type: 'text', value: 'Footnote text' }], + }, + ], + }, + ], + }; + const tree = { + type: 'root', + children: [layout, { type: 'text', value: '\n' }, footnotes], + }; + + transformer()(tree); + + assert.equal(tree.children.includes(footnotes), false); + assert.equal(layout.children.at(-1), footnotes); + }); +}); diff --git a/src/generators/jsx-ast/utils/transformer.mjs b/src/generators/jsx-ast/utils/transformer.mjs index b5c732ff..53dadee7 100644 --- a/src/generators/jsx-ast/utils/transformer.mjs +++ b/src/generators/jsx-ast/utils/transformer.mjs @@ -3,6 +3,23 @@ import { visit } from 'unist-util-visit'; import { TAG_TRANSFORMS } from '../constants.mjs'; +/** + * Checks whether a HAST node is the generated GFM footnotes section. + * @param {import('hast').Element} node + */ +const isFootnotesSection = node => + node?.type === 'element' && + node.tagName === 'section' && + (node.properties?.dataFootnotes !== undefined || + node.properties?.className?.includes('footnotes')); + +/** + * Finds the generated page Layout node. + * @param {import('hast').Root} tree + */ +const findLayout = tree => + tree.children.find(node => node.name === 'Layout' && node.children); + /** * @template {import('unist').Node} T * @param {T} tree @@ -43,14 +60,17 @@ const transformer = tree => { } }); - // Are there footnotes? - if (tree.children.at(-1).tagName === 'section') { - const section = tree.children.pop(); - // If so, move it into the proper location - // Root -> Article -> Main content - tree.children[2]?.children[1]?.children[0]?.children?.push( - ...section.children - ); + const index = tree.children.findLastIndex(isFootnotesSection); + + if (index !== -1) { + const [section] = tree.children.splice(index, 1); + const layout = findLayout(tree); + + if (layout) { + layout.children.push(section); + } else { + tree.children.push(section); + } } };