Skip to content

Commit b2c98cd

Browse files
committed
[WIP] mdx generator
1 parent 6f70de4 commit b2c98cd

File tree

8 files changed

+301
-4
lines changed

8 files changed

+301
-4
lines changed

package-lock.json

Lines changed: 163 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
"hast-util-to-string": "^3.0.1",
4848
"hastscript": "^9.0.1",
4949
"html-minifier-terser": "^7.2.0",
50+
"mdast-util-to-markdown": "^2.1.2",
51+
"mdast-util-mdx-jsx": "^3.2.0",
5052
"rehype-stringify": "^10.0.1",
5153
"remark-gfm": "^4.0.1",
5254
"remark-parse": "^11.0.0",

src/generators/index.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import apiLinks from './api-links/index.mjs';
1111
import oramaDb from './orama-db/index.mjs';
1212
import astJs from './ast-js/index.mjs';
1313
import llmsTxt from './llms-txt/index.mjs';
14+
import mdx from './mdx/index.mjs';
1415

1516
export const publicGenerators = {
1617
'json-simple': jsonSimple,
@@ -23,6 +24,7 @@ export const publicGenerators = {
2324
'api-links': apiLinks,
2425
'orama-db': oramaDb,
2526
'llms-txt': llmsTxt,
27+
mdx: mdx,
2628
};
2729

2830
export const allGenerators = {

src/generators/legacy-html/utils/buildContent.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ export default (headNodes, metadataEntries, remark) => {
209209
// Parses the metadata pieces of each node and the content
210210
metadataEntries.map(entry => {
211211
// Deep clones the content nodes to avoid affecting upstream nodes
212-
const content = JSON.parse(JSON.stringify(entry.content));
212+
const content = structuredClone(entry.content);
213213

214214
// Parses the Heading nodes into Heading elements
215215
visit(content, createQueries.UNIST.isHeading, buildHeading);

src/generators/mdx/constants.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const STABILITY_LEVELS = [
2+
'danger', // Deprecated
3+
'warning', // Experimental
4+
'success', // Stable
5+
'info', //
6+
];

src/generators/mdx/index.mjs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { groupNodesByModule } from '../../utils/generators.mjs';
2+
import buildContent from './utils/buildContent.mjs';
3+
import { toMarkdown } from 'mdast-util-to-markdown';
4+
import { mdxJsxToMarkdown } from 'mdast-util-mdx-jsx';
5+
6+
/**
7+
* This generator generates an MDX AST from an input MDAST
8+
*
9+
* @typedef {Array<ApiDocMetadataEntry>} Input
10+
*
11+
* @type {GeneratorMetadata<Input, string>}
12+
*/
13+
export default {
14+
name: 'llms-txt',
15+
version: '1.0.0',
16+
description: 'Generates a MDX file from the input AST',
17+
dependsOn: 'ast',
18+
19+
/**
20+
* Generates a MDX AST
21+
*
22+
* @param {Input} entries
23+
* @returns {Promise<string[]>} Array of generated content
24+
*/
25+
async generate(entries) {
26+
// Pre-process all data once
27+
const headNodes = entries
28+
.filter(node => node.heading.depth === 1)
29+
.sort((a, b) => a.heading.data.name.localeCompare(b.heading.data.name));
30+
31+
const modules = groupNodesByModule(entries);
32+
33+
// Process nodes in parallel for better performance
34+
const results = await Promise.all(
35+
headNodes.map(node => buildContent(headNodes, modules.get(node.api)))
36+
);
37+
38+
console.log(toMarkdown(results[0], { extensions: [mdxJsxToMarkdown()] }));
39+
return results;
40+
},
41+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
import { u as createTree } from 'unist-builder';
4+
import { SKIP, visit } from 'unist-util-visit';
5+
import createQueries from '../../../utils/queries/index.mjs';
6+
import { createJSXElement } from './mdxUtilities.mjs';
7+
import { STABILITY_LEVELS } from '../constants.mjs';
8+
9+
/**
10+
*
11+
* @param {import('@types/mdast').Blockquote} node The HTML AST tree of the Stability Index content
12+
* @param {number} index The index of the current node
13+
* @param {import('unist').Parent} parent The parent node of the current node
14+
*/
15+
const visitStabilityNode = (node, index, parent) => {
16+
parent.children.splice(
17+
index,
18+
1,
19+
createJSXElement('AlertBox', {
20+
children: node.data.description,
21+
level: STABILITY_LEVELS[node.data.index],
22+
title: node.data.index,
23+
})
24+
);
25+
return [SKIP];
26+
};
27+
28+
/**
29+
* Process a single content entry by applying all transformations
30+
* @param {import('unist').Node} content The content to process
31+
* @returns {import('unist').Node} The processed content
32+
*/
33+
const processContent = content => {
34+
const clonedContent = structuredClone(content);
35+
visit(clonedContent, createQueries.UNIST.isStabilityNode, visitStabilityNode);
36+
return clonedContent;
37+
};
38+
39+
/**
40+
* Transforms API metadata entries into markdown content with special handling for stability nodes
41+
* @param {any} _ Unused parameter
42+
* @param {Array<ApiDocMetadataEntry>} metadataEntries Entries to transform
43+
* @returns {import('unist').Node} Root node with processed content
44+
*/
45+
export default (_, metadataEntries) => {
46+
const rootNode = createTree(
47+
'root',
48+
metadataEntries.map(entry => processContent(entry.content))
49+
);
50+
51+
return rootNode;
52+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
3+
import { u as createTree } from 'unist-builder';
4+
5+
/**
6+
* Creates an MDX JSX element.
7+
*
8+
* @param {string} name - The name of the JSX element
9+
* @param {{
10+
* inline?: boolean,
11+
* children?: string | import('unist').Node[],
12+
* [key: string]: string
13+
* }} [options={}] - Options including type, children, and JSX attributes
14+
* @returns {import('unist').Node} The created MDX JSX element node
15+
*/
16+
export const createJSXElement = (
17+
name,
18+
{ inline = false, children = [], ...attributes } = {}
19+
) => {
20+
const processedChildren =
21+
typeof children === 'string'
22+
? [createTree('text', { value: children })]
23+
: (children ?? []);
24+
25+
const attrs = Object.entries(attributes).map(([key, value]) =>
26+
createTree('mdxJsxAttribute', { name: key, value: String(value) })
27+
);
28+
29+
return createTree(inline ? 'mdxJsxTextElement' : 'mdxJsxFlowElement', {
30+
name,
31+
attributes: attrs,
32+
children: processedChildren,
33+
});
34+
};

0 commit comments

Comments
 (0)