@mui/internal-docs-infra
Version:
MUI Infra - internal documentation creation tools.
352 lines (333 loc) • 15.2 kB
JavaScript
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
};
}