forked from mui/base-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpropsReferenceTableProcessor.mjs
More file actions
174 lines (147 loc) · 5.43 KB
/
propsReferenceTableProcessor.mjs
File metadata and controls
174 lines (147 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* propsReferenceTableProcessor.mjs - Process inline PropsReferenceTable components
*
* This module handles converting inline props reference data from MDX PropsReferenceTable
* components into markdown tables for documentation.
*/
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import * as mdx from './mdxNodeHelpers.mjs';
/**
* Parse a markdown string into an AST
* @param {string} markdown - Markdown string to parse
* @returns {Object} The root content node of the parsed AST
*/
function parseMarkdown(markdown) {
// Parse markdown into an AST
const processor = unified().use(remarkParse);
const result = processor.parse(markdown);
return result.children;
}
/**
* Recursively convert an estree expression into a JavaScript object
* @param {Object} estree - The estree node to convert
* @returns {Object} The converted JavaScript object
*/
function convertEstreeToObject(estree) {
// Get the main expression from the estree program body
if (!estree || !estree.body || !estree.body[0] || !estree.body[0].expression) {
throw new Error('Invalid estree structure - missing expression');
}
const expression = estree.body[0].expression;
return convertExpressionNode(expression);
}
/**
* Convert an expression node to a JavaScript value
* @param {Object} node - The expression node
* @returns {any} The converted JavaScript value
*/
function convertExpressionNode(node) {
if (!node || !node.type) {
throw new Error('Invalid expression node - missing type');
}
switch (node.type) {
case 'ObjectExpression': {
const obj = {};
// Convert each property in the object
for (const prop of node.properties) {
if (prop.type !== 'Property') {
throw new Error(`Unsupported property type: ${prop.type}`);
}
// Get the property key
let key;
if (prop.key.type === 'Identifier') {
key = prop.key.name;
} else if (prop.key.type === 'Literal') {
key = prop.key.value;
} else {
throw new Error(`Unsupported key type: ${prop.key.type}`);
}
// Get the property value
const value = convertExpressionNode(prop.value);
// Add to the object
obj[key] = value;
}
return obj;
}
case 'ArrayExpression':
// Convert each element in the array
return node.elements.map((element) => convertExpressionNode(element));
case 'Literal':
// Return literals directly
return node.value;
case 'TemplateLiteral':
// For simple template literals with no expressions
if (node.quasis.length === 1 && node.expressions.length === 0) {
return node.quasis[0].value.raw;
}
// For complex template literals, return a simplified representation
return node.quasis.map((q) => q.value.raw).join('…');
case 'Identifier':
// For identifiers like undefined, null, etc.
return node.name;
default:
throw new Error(`Unsupported expression type: ${node.type}`);
}
}
/**
* Transforms a PropsReferenceTable component into a markdown table
* @param {Object} node - The PropsReferenceTable JSX node from MDX
* @returns {Array} Array of markdown nodes to replace the PropsReferenceTable component
*/
export function processPropsReferenceTable(node) {
// Extract the data attribute which contains props definitions
const dataAttr = node.attributes?.find((attr) => attr.name === 'data');
const typeAttr = node.attributes?.find((attr) => attr.name === 'type')?.value || 'props';
// If no data attribute is found, throw an error
if (!dataAttr) {
throw new Error('PropsReferenceTable: No data provided');
}
// Process the data object from the AST
let propsData = {};
if (dataAttr.type === 'mdxJsxAttribute' && dataAttr.value) {
try {
if (
dataAttr.value.type === 'mdxJsxAttributeValueExpression' &&
dataAttr.value.data &&
dataAttr.value.data.estree
) {
// Convert the estree to a JavaScript object
propsData = convertEstreeToObject(dataAttr.value.data.estree);
} else {
throw new Error('PropsReferenceTable data must be a static JavaScript object');
}
} catch (err) {
throw new Error(`Error processing PropsReferenceTable data: ${err.message}`);
}
} else {
throw new Error('PropsReferenceTable data attribute must be a valid JSX attribute');
}
// Generate markdown tables
const tables = [];
// Add heading based on the type
const heading = typeAttr === 'return' ? 'Return Value' : 'Props';
tables.push(mdx.paragraph([mdx.strong(`${heading}:`)]));
// Convert props data to table rows
const propsRows = Object.entries(propsData).map(([propName, propDef]) => {
const row = [propName, propDef.type ? mdx.inlineCode(propDef.type) : '-'];
// Add default column for props type
if (typeAttr === 'props') {
row.push(propDef.default ? mdx.inlineCode(propDef.default) : '-');
}
// Add description
row.push(parseMarkdown(propDef.description || '-'));
return row;
});
// Define columns based on type
const headers =
typeAttr === 'props'
? ['Prop', 'Type', 'Default', 'Description']
: ['Property', 'Type', 'Description'];
// Define column alignments
const alignments =
typeAttr === 'props' ? ['left', 'left', 'left', 'left'] : ['left', 'left', 'left'];
const tableNode = mdx.table(headers, propsRows, alignments);
tables.push(tableNode);
return tables;
}