UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

352 lines (333 loc) 15.2 kB
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper"; import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import { rewriteImportsToSameDirectory } from "./rewriteImports.js"; import { isJavaScriptModule } from "./resolveModulePath.js"; import { getFileNameFromUrl } from "./getFileNameFromUrl.js"; /** * Processes imports based on the specified storage mode, automatically handling * source rewriting when needed (e.g., for 'flat' mode). * * @param source - The original source code * @param importResult - The result from parseImports * @param resolvedPathsMap - Map from import paths to resolved file paths * @param storeAt - How to process the imports * @returns Object with processed source and extraFiles mapping */ export function processRelativeImports(source, importResult, resolvedPathsMap, storeAt) { var extraFiles = {}; // For flat mode, we need to handle naming conflicts intelligently if (storeAt === 'flat') { var result = processFlatMode(importResult, resolvedPathsMap); // Create import path mapping for rewriting var importPathMapping = new Map(); // Build a reverse mapping from resolved paths to extraFiles keys var resolvedToExtraFile = new Map(); Object.entries(result.extraFiles).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), extraFileKey = _ref2[0], fileUrl = _ref2[1]; var resolvedPath = fileUrl.replace('file://', ''); resolvedToExtraFile.set(resolvedPath, extraFileKey); }); // For each import, find its resolved path and map to the corresponding extraFile key Object.entries(importResult).forEach(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), relativePath = _ref4[0], importInfo = _ref4[1]; var resolvedPath = resolvedPathsMap.get(importInfo.path); if (resolvedPath) { var extraFileKey = resolvedToExtraFile.get(resolvedPath); if (extraFileKey) { // For JavaScript modules, remove the extension; for other files (CSS, JSON, etc.), keep it var isJavascriptModule = isJavaScriptModule(relativePath); var newPath = extraFileKey; if (isJavascriptModule) { // Handle TypeScript declaration files (.d.ts) properly if (newPath.endsWith('.d.ts')) { newPath = newPath.replace(/\.d\.ts$/, ''); } else { newPath = newPath.replace(/\.[^/.]+$/, ''); } } // For non-JS modules (CSS, JSON, etc.), keep the full path with extension importPathMapping.set(relativePath, newPath); } } }); // Rewrite the source with the mapping var rewrittenSource = rewriteImportsToSameDirectory(source, importPathMapping); return { processedSource: rewrittenSource, extraFiles: result.extraFiles }; } // Process each import and generate extraFiles for non-flat modes Object.entries(importResult).forEach(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), relativePath = _ref6[0], importInfo = _ref6[1]; var resolvedPath = resolvedPathsMap.get(importInfo.path); if (resolvedPath) { var fileExtension = getFileNameFromUrl(resolvedPath).extension; var isJavascriptModule = isJavaScriptModule(relativePath); var keyPath; if (!isJavascriptModule) { // For static assets (CSS, JSON, etc.), use the original import path as-is since it already has the extension switch (storeAt) { case 'canonical': case 'import': keyPath = relativePath; break; default: keyPath = relativePath; } } else { // For JS/TS modules, apply the existing logic switch (storeAt) { case 'canonical': // Show the full resolved path including index files when they exist // e.g., import '../Component' resolved to '/src/Component/index.js' // becomes extraFiles: { '../Component/index.js': 'file:///src/Component/index.js' } keyPath = "".concat(relativePath).concat(resolvedPath.endsWith("/index".concat(fileExtension)) ? "/index".concat(fileExtension) : fileExtension); break; case 'import': // Use the original import path with the actual file extension // e.g., import '../Component' with '/src/Component/index.js' // becomes extraFiles: { '../Component.js': 'file:///src/Component/index.js' } keyPath = "".concat(relativePath).concat(fileExtension); break; default: keyPath = "".concat(relativePath).concat(fileExtension); } } extraFiles[keyPath] = "file://".concat(resolvedPath); } }); return { processedSource: source, extraFiles: extraFiles }; } /** * Processes flat mode with intelligent conflict resolution */ function processFlatMode(importResult, resolvedPathsMap) { var extraFiles = {}; var fileMapping = []; // First pass: collect all files and their path segments Object.entries(importResult).forEach(function (_ref7) { var _ref8 = _slicedToArray(_ref7, 2), relativePath = _ref8[0], importInfo = _ref8[1]; var resolvedPath = resolvedPathsMap.get(importInfo.path); if (resolvedPath) { var fileExtension = getFileNameFromUrl(resolvedPath).extension; var pathSegments = resolvedPath.split('/').filter(Boolean); fileMapping.push({ resolvedPath: resolvedPath, extension: fileExtension, segments: pathSegments, originalImportPath: relativePath }); } }); // Second pass: determine candidate names and group by conflicts var candidateNames = new Map(); var nameGroups = new Map(); for (var _i = 0, _fileMapping = fileMapping; _i < _fileMapping.length; _i++) { var file = _fileMapping[_i]; var fileName = file.segments[file.segments.length - 1]; var isIndexFile = fileName.startsWith('index.'); var candidateName = void 0; if (isIndexFile) { // Check if the original import was a direct index file (e.g., "./index.ext") var originalImportParts = file.originalImportPath.split('/'); var isDirectIndexImport = originalImportParts.length === 2 && originalImportParts[0] === '.' && originalImportParts[1].startsWith('index.'); if (isDirectIndexImport) { // For direct index imports like "./index.ext", keep the original name candidateName = "index".concat(file.extension); } else { // For nested index files like "./test/index.ext", use parent directory + extension var parentDir = file.segments[file.segments.length - 2]; candidateName = "".concat(parentDir).concat(file.extension); } } else { candidateName = fileName; } candidateNames.set(file.resolvedPath, candidateName); if (!nameGroups.has(candidateName)) { nameGroups.set(candidateName, []); } nameGroups.get(candidateName).push(file.resolvedPath); } // Third pass: resolve conflicts for all files in conflicting groups var finalNames = new Map(); nameGroups.forEach(function (paths, candidateName) { if (paths.length === 1) { // No conflict, use the candidate name finalNames.set(paths[0], candidateName); } else { // Conflict detected, find optimal minimal distinguishing paths for all files var conflictingFiles = paths.map(function (resolvedPath) { return fileMapping.find(function (f) { return f.resolvedPath === resolvedPath; }); }); // Check if we can resolve conflicts by treating some files differently // This specifically handles cases like: // - /path/to/a/Component.js and /path/to/Component.js (parent-child relationship) // Find files that are "shorter" (parent level) compared to others var minLength = Math.min.apply(Math, _toConsumableArray(conflictingFiles.map(function (f) { return f.segments.length; }))); var maxLengthForSmart = Math.max.apply(Math, _toConsumableArray(conflictingFiles.map(function (f) { return f.segments.length; }))); if (maxLengthForSmart > minLength) { // We have files at different depths, check if it's a parent-child scenario var shorterFiles = conflictingFiles.filter(function (file) { return file.segments.length === minLength; }); var longerFiles = conflictingFiles.filter(function (file) { return file.segments.length > minLength; }); if (shorterFiles.length === 1 && longerFiles.length >= 1) { // Check if the shorter file is truly a "parent" of the longer files var shorterFile = shorterFiles[0]; var shorterPath = shorterFile.segments.slice(0, -1).join('/'); // Remove filename // Check if all longer files share the same prefix as the shorter file var allLongerFilesAreChildren = longerFiles.every(function (longerFile) { var longerPath = longerFile.segments.slice(0, shorterFile.segments.length - 1).join('/'); return longerPath === shorterPath; }); if (allLongerFilesAreChildren) { // This is a true parent-child scenario, apply smart resolution // For longer files, find distinguishing index var _distinguishingIndex = -1; var maxLongerLength = Math.max.apply(Math, _toConsumableArray(longerFiles.map(function (f) { return f.segments.length; }))); var _loop = function _loop(i) { var segmentsAtIndex = new Set(longerFiles.map(function (f) { return f.segments[i]; }).filter(Boolean)); if (segmentsAtIndex.size === longerFiles.length) { _distinguishingIndex = i; return 1; // break } }; for (var i = 0; i < maxLongerLength; i += 1) { if (_loop(i)) break; } if (_distinguishingIndex !== -1) { // Generate names for longer files using distinguishing segment var _iterator = _createForOfIteratorHelper(longerFiles), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var _file = _step.value; var _fileName = _file.segments[_file.segments.length - 1]; var _isIndexFile = _fileName.startsWith('index.'); var distinguishingSegment = _file.segments[_distinguishingIndex]; var finalName = void 0; if (_isIndexFile) { // Check if this was a direct index import var _originalImportParts = _file.originalImportPath.split('/'); var _isDirectIndexImport = _originalImportParts.length === 2 && _originalImportParts[0] === '.' && _originalImportParts[1].startsWith('index.'); if (_isDirectIndexImport) { finalName = "".concat(distinguishingSegment, "/index").concat(_file.extension); } else { var _parentDir = _file.segments[_file.segments.length - 2]; finalName = "".concat(distinguishingSegment, "/").concat(_parentDir).concat(_file.extension); } } else { finalName = "".concat(distinguishingSegment, "/").concat(_fileName); } finalNames.set(_file.resolvedPath, finalName); } // For shorter files, use the candidate name as-is (no conflicts after disambiguation) } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var _iterator2 = _createForOfIteratorHelper(shorterFiles), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var shortFile = _step2.value; finalNames.set(shortFile.resolvedPath, candidateName); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return; // Successfully resolved } } } } // Fallback to original algorithm if smart resolution fails var distinguishingIndex = -1; var maxLength = Math.max.apply(Math, _toConsumableArray(conflictingFiles.map(function (f) { return f.segments.length; }))); var _loop2 = function _loop2(_i2) { var segmentsAtIndex = new Set(conflictingFiles.map(function (f) { return f.segments[_i2]; }).filter(Boolean)); if (segmentsAtIndex.size === conflictingFiles.length) { distinguishingIndex = _i2; return 1; // break } }; for (var _i2 = 0; _i2 < maxLength; _i2 += 1) { if (_loop2(_i2)) break; } if (distinguishingIndex === -1) { throw new Error("Cannot find distinguishing segment for files: ".concat(paths.join(', '))); } // Generate names using the distinguishing segment var _iterator3 = _createForOfIteratorHelper(conflictingFiles), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _file2 = _step3.value; var _fileName2 = _file2.segments[_file2.segments.length - 1]; var _isIndexFile2 = _fileName2.startsWith('index.'); var _distinguishingSegment = _file2.segments[distinguishingIndex]; var _finalName = void 0; if (_isIndexFile2) { // Check if this was a direct index import var _originalImportParts2 = _file2.originalImportPath.split('/'); var _isDirectIndexImport2 = _originalImportParts2.length === 2 && _originalImportParts2[0] === '.' && _originalImportParts2[1].startsWith('index.'); if (_isDirectIndexImport2) { _finalName = "".concat(_distinguishingSegment, "/index").concat(_file2.extension); } else { var _parentDir2 = _file2.segments[_file2.segments.length - 2]; _finalName = "".concat(_distinguishingSegment, "/").concat(_parentDir2).concat(_file2.extension); } } else { _finalName = "".concat(_distinguishingSegment, "/").concat(_fileName2); } finalNames.set(_file2.resolvedPath, _finalName); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } } }); // Fourth pass: build the extraFiles mapping finalNames.forEach(function (finalName, resolvedPath) { extraFiles["./".concat(finalName)] = "file://".concat(resolvedPath); }); return { processedSource: '', // Will be set by caller after rewriting extraFiles: extraFiles }; }