UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

109 lines (104 loc) 4.59 kB
import { formatProperties, formatParameters, parseMarkdownToHast, applyDescriptionReplacements } from "./format.mjs"; import { formatType } from "./formatType.mjs"; import { isFunctionType, isAnonymousObjectType, isObjectType } from "./typeGuards.mjs"; import { rewriteTypeStringsDeep } from "./rewriteTypes.mjs"; export async function formatHookData(hook, typeNameMap, rewriteContext, options = {}) { const { descriptionReplacements, formatting, externalTypes } = options; const { exportNames } = rewriteContext; const descriptionText = hook.documentation?.description ? applyDescriptionReplacements(hook.documentation.description, descriptionReplacements) : undefined; const description = descriptionText ? await parseMarkdownToHast(descriptionText) : undefined; // Handle hook overloads: pick the signature with the most parameters, // then mark parameters as optional if they don't appear in all signatures. const callSignatures = hook.type.callSignatures; const signature = callSignatures.reduce((longest, current) => current.parameters.length > longest.parameters.length ? current : longest); const parameters = signature.parameters; // Determine which parameters are optional by checking if they exist in all overloads const minParamCount = Math.min(...callSignatures.map(sig => sig.parameters.length)); const optionalFromIndex = minParamCount; let formattedParameters; let formattedProperties; if (parameters.length === 1 && isObjectType(parameters[0].type) && isAnonymousObjectType(parameters[0].type)) { formattedProperties = await formatProperties(parameters[0].type.properties, { exportNames, typeNameMap, formatting, externalTypes, descriptionReplacements }); } else { formattedParameters = await formatParameters(parameters, { exportNames, typeNameMap, formatting, externalTypes, descriptionReplacements }); // Mark parameters as optional if they don't appear in all overloads parameters.forEach((param, index) => { if (index >= optionalFromIndex) { const entry = formattedParameters.find(p => p.name === param.name); if (entry) { entry.optional = true; } } }); } let formattedReturnValue; let returnValueText; // Only expand anonymous object types into a property table. // Named types (like class instances `DialogHandle<Payload>`) are kept as type references. const returnType = signature.returnValueType; const shouldExpandReturnType = isObjectType(returnType) && isAnonymousObjectType(returnType) && returnType.properties && returnType.properties.length > 0; if (shouldExpandReturnType) { formattedReturnValue = await formatProperties(returnType.properties, { exportNames, typeNameMap, formatting, externalTypes, descriptionReplacements }); } else { // Format type as plain text - highlighting is deferred to loadServerTypes // Only expand anonymous objects (no type name) — named types should be shown as references. const shouldExpand = isObjectType(returnType) && isAnonymousObjectType(returnType); returnValueText = formatType(signature.returnValueType, { expandObjects: shouldExpand, exportNames, typeNameMap, externalTypesCollector: externalTypes }); formattedReturnValue = returnValueText; } // Get return value description from @returns tag const returnsTag = hook.documentation?.tags?.find(tag => tag.name === 'returns'); const returnValueDescriptionText = returnsTag?.value; const returnValueDescription = returnValueDescriptionText ? await parseMarkdownToHast(returnValueDescriptionText) : undefined; const raw = { name: hook.name, description, descriptionText, ...(formattedParameters && { parameters: formattedParameters }), ...(formattedProperties && { expandedProperties: formattedProperties }), returnValue: formattedReturnValue, returnValueText, returnValueDescription, returnValueDescriptionText }; // Post-process type strings to align naming across re-exports return rewriteTypeStringsDeep(raw, rewriteContext); } export function isPublicHook(exportNode) { const isPublic = exportNode.documentation?.visibility !== 'private' && exportNode.documentation?.visibility !== 'internal'; const hasIgnoreTag = exportNode.documentation?.tags?.some(tag => tag.name === 'ignore'); return isFunctionType(exportNode.type) && exportNode.name.startsWith('use') && !hasIgnoreTag && isPublic; }