@mui/internal-docs-infra
Version:
MUI Infra - internal documentation creation tools.
155 lines (140 loc) • 5.05 kB
JavaScript
/**
* Metadata merging utility for positioning metadata files relative to source files
*/
import { calculateMaxSourceBackNavigation, removeBackNavigationPrefix, buildPath, calculateMetadataBackNavigation, splitPath } from "./pathUtils.mjs";
/**
* Options for merging metadata files
*/
/**
* Merge metadata files into a variant with proper positioning
*
* @param variant - The variant containing source files and potentially mixed metadata/non-metadata files
* @param metadataFiles - Additional metadata files to merge in
* @param options - Options for metadata positioning
* @returns A variant with all metadata files properly positioned
*/
/**
* Extract metadata files from a variant, scoping them according to metadataPrefix
*
* @param variant - The variant containing mixed source and metadata files
* @returns An object with the cleaned variant and extracted metadata
*/
export function extractCodeMetadata(variant) {
const {
metadataPrefix
} = variant;
const extractedMetadata = {};
const nonMetadataFiles = {};
if (!variant.extraFiles) {
return {
variant: {
...variant,
extraFiles: {}
},
metadata: {}
};
}
// Calculate how much back navigation to remove using pathUtils
let backLevelsToRemove = calculateMaxSourceBackNavigation(variant.extraFiles || {});
if (metadataPrefix) {
// Add metadataPrefix levels if present
backLevelsToRemove += splitPath(metadataPrefix).length;
}
// Process all extraFiles
for (const [relativePath, fileContent] of Object.entries(variant.extraFiles)) {
const file = typeof fileContent === 'string' ? {
source: fileContent
} : fileContent;
if (file.metadata) {
const scopedPath = removeBackNavigationPrefix(relativePath, backLevelsToRemove);
// Remove metadata flag when extracting
const {
metadata: metadataFlag,
...cleanFile
} = file;
extractedMetadata[scopedPath] = cleanFile;
} else {
nonMetadataFiles[relativePath] = file;
}
}
return {
variant: {
...variant,
extraFiles: nonMetadataFiles
},
metadata: extractedMetadata
};
}
export function mergeCodeMetadata(variant, metadataFiles = {}, options = {}) {
// Determine which metadataPrefix to use
const targetMetadataPrefix = options.metadataPrefix ?? variant.metadataPrefix;
// Check if we need to re-extract metadata due to metadataPrefix change
const needsReextraction = options.metadataPrefix !== undefined && options.metadataPrefix !== variant.metadataPrefix;
// If metadataPrefix is changing, extract existing metadata and reposition everything
let workingVariant = variant;
let existingMetadata = {};
if (needsReextraction && variant.extraFiles) {
// Extract existing metadata using the old metadataPrefix
const extracted = extractCodeMetadata(variant);
workingVariant = extracted.variant;
existingMetadata = extracted.metadata;
}
// Calculate the positioning level for metadata files
const metadataBackNavigation = calculateMetadataBackNavigation(workingVariant.extraFiles, targetMetadataPrefix);
// Collect all metadata files that need positioning
const allMetadataFiles = {};
const nonMetadataFiles = {};
const positionedMetadataFiles = {};
// Process existing extraFiles from working variant
if (workingVariant.extraFiles) {
for (const [relativePath, fileContent] of Object.entries(workingVariant.extraFiles)) {
const file = typeof fileContent === 'string' ? {
source: fileContent
} : fileContent;
if (file.metadata) {
// If we're not changing metadataPrefix, keep existing metadata files where they are
if (!needsReextraction) {
positionedMetadataFiles[relativePath] = file;
} else {
// Only collect for repositioning if metadataPrefix is changing
allMetadataFiles[relativePath] = file;
}
} else {
nonMetadataFiles[relativePath] = file;
}
}
}
// Add extracted metadata (if any) for repositioning
for (const [filePath, file] of Object.entries(existingMetadata)) {
allMetadataFiles[filePath] = {
...(typeof file === 'string' ? {
source: file
} : file),
metadata: true
};
}
// Add additional metadata files for positioning
for (const [filePath, file] of Object.entries(metadataFiles)) {
allMetadataFiles[filePath] = {
...(typeof file === 'string' ? {
source: file
} : file),
metadata: true
};
}
// Position new metadata files at the calculated level using buildPath
for (const [originalPath, file] of Object.entries(allMetadataFiles)) {
const metadataPath = buildPath(metadataBackNavigation, originalPath);
positionedMetadataFiles[metadataPath] = file;
}
// Combine all files
const finalExtraFiles = {
...nonMetadataFiles,
...positionedMetadataFiles
};
return {
...workingVariant,
extraFiles: finalExtraFiles,
metadataPrefix: targetMetadataPrefix
};
}