mirror of
https://github.com/aphrody-labs/base-ui.git
synced 2026-10-14 13:19:31 +00:00
175 lines
5.4 KiB
JavaScript
175 lines
5.4 KiB
JavaScript
/**
|
|
* 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;
|
|
}
|