UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

147 lines (139 loc) 6.14 kB
import { toText } from 'hast-util-to-text'; import { diffHast } from "./diffHast.mjs"; import { embedTransformsInRoot, splitTransformsForEmbed } from "./embedTransforms.mjs"; /** * Pure function to identify which variants need transformation. * Returns entries of variants that have transforms requiring processing. * * Skips variants whose transforms have already been embedded into * `source.data.transforms` (i.e. already processed). Also requires at least * one transform entry to still carry a `delta` — manifest-only entries * (with `delta` stripped after embedding) are ignored. */ export function getVariantsToTransform(parsedCode) { const hasDeltaEntries = transforms => !!transforms && Object.values(transforms).some(entry => entry && typeof entry === 'object' && 'delta' in entry && entry.delta && typeof entry.delta === 'object' && Object.keys(entry.delta).length > 0); const sourceIsUnembeddedHast = source => !!source && typeof source === 'object' && !('hastJson' in source) && !('hastCompressed' in source) && !(source.data && source.data.transforms); return Object.entries(parsedCode).filter(([, variantCode]) => { if (!variantCode || typeof variantCode !== 'object') { return false; } const mainSourceNeedsTransform = hasDeltaEntries(variantCode.transforms) && typeof variantCode.source !== 'string' && sourceIsUnembeddedHast(variantCode.source); const extraFilesNeedTransform = variantCode.extraFiles ? Object.values(variantCode.extraFiles).some(fileContent => typeof fileContent === 'object' && fileContent && hasDeltaEntries(fileContent.transforms) && typeof fileContent.source !== 'string' && sourceIsUnembeddedHast(fileContent.source)) : false; return mainSourceNeedsTransform || extraFilesNeedTransform; }); } /** * Pure async function to transform a single variant's code and extraFiles. * Returns the transformed variant or the original if transformation fails. */ export async function computeVariantDeltas(variant, variantCode, parseSource) { // Type guard if (typeof variantCode !== 'object' || !variantCode) { return variantCode; } let mainTransformResult; let transformedExtraFiles; // Process main source transforms if applicable if (variantCode.transforms && variantCode.source && typeof variantCode.source !== 'string' && !('hastJson' in variantCode.source) && !('hastCompressed' in variantCode.source)) { const hastNodes = variantCode.source; const sourceString = toText(hastNodes, { whitespace: 'pre' }); const computed = await diffHast(sourceString, hastNodes, variant, // fileName variantCode.transforms, parseSource); const split = splitTransformsForEmbed(computed); if (split) { embedTransformsInRoot(hastNodes, split.embedded); mainTransformResult = split.manifest; } else { mainTransformResult = undefined; } } // Process extraFiles transforms if applicable if (variantCode.extraFiles) { transformedExtraFiles = await Promise.all(Object.entries(variantCode.extraFiles).map(async ([fileName, fileContent]) => { if (typeof fileContent === 'object' && fileContent && fileContent.transforms && fileContent.source && typeof fileContent.source !== 'string' && !('hastJson' in fileContent.source) && !('hastCompressed' in fileContent.source)) { try { const extraHastNodes = fileContent.source; const extraSourceString = toText(extraHastNodes, { whitespace: 'pre' }); const computedExtra = await diffHast(extraSourceString, extraHastNodes, fileName, fileContent.transforms, parseSource); const splitExtra = splitTransformsForEmbed(computedExtra); if (splitExtra) { embedTransformsInRoot(extraHastNodes, splitExtra.embedded); return [fileName, { ...fileContent, transforms: splitExtra.manifest }]; } // No surviving entries — drop transforms from the extra file. const { transforms: droppedTransforms, ...rest } = fileContent; return [fileName, rest]; } catch (error) { console.error(`Failed to transform extraFile ${fileName}:`, error); return [fileName, fileContent]; } } return [fileName, fileContent]; })).then(entries => Object.fromEntries(entries)); } // Update the variant with the computed results const transformedVariant = { ...variantCode, ...(mainTransformResult !== undefined && { transforms: mainTransformResult }), ...(transformedExtraFiles && { extraFiles: transformedExtraFiles }) }; return transformedVariant; } /** * Computes transform deltas for all variants in the parsed code. * This function generates the transformation data that can be applied later. * * @param parsedCode - The parsed code object containing variants * @param parseSource - The parser function to parse source strings * @returns A promise that resolves to the code with computed transforms */ export async function computeHastDeltas(parsedCode, parseSource) { const variantsToTransform = getVariantsToTransform(parsedCode); if (variantsToTransform.length === 0) { // No variants need transformation return parsedCode; } // Process transformations for all variants const results = await Promise.all(variantsToTransform.map(async ([variant, variantCode]) => { try { const transformedVariant = await computeVariantDeltas(variant, variantCode, parseSource); return { variant, transformedVariant }; } catch (error) { // Keep original variant if transformation fails console.error(`Failed to transform variant ${variant}:`, error); return { variant, transformedVariant: variantCode }; } })); // Apply the transformations to create the enhanced code const enhancedCode = { ...parsedCode }; for (const { variant, transformedVariant } of results) { enhancedCode[variant] = transformedVariant; } return enhancedCode; }