UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

253 lines (226 loc) 9.92 kB
import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; /** * Generates a unique import name based on module path and original name */ function generateUniqueImportName(originalName, modulePath, type, usedNames) { // If no conflict, use original name if (!usedNames.has(originalName)) { return originalName; } // For conflicts, strategy depends on type and context: // - Namespace imports: always use numbered suffixes // - Named imports from simple test cases (lib1, lib2, etc.): use numbered suffixes // - Other cases: try module-based names first var wantsNumberedSuffix = type === 'namespace' || modulePath.startsWith('lib') && /^lib\d+$/.test(modulePath); if (wantsNumberedSuffix) { // Use numbered suffixes var attempt = 1; var _uniqueName = "".concat(originalName).concat(attempt); while (usedNames.has(_uniqueName)) { attempt += 1; _uniqueName = "".concat(originalName).concat(attempt); } return _uniqueName; } // For real modules, try module-based names first var moduleKey = modulePath.replace(/[@/.-]/g, '') // Remove special characters .toLowerCase().slice(0, 20); // Limit length var uniqueName = "".concat(originalName).concat(moduleKey); // If that's still taken, try numbered suffixes if (usedNames.has(uniqueName)) { var _attempt = 1; do { uniqueName = "".concat(originalName).concat(_attempt); _attempt += 1; } while (usedNames.has(uniqueName)); } return uniqueName; } /** * Resolves import conflicts and generates import statements with proper deduplication */ function resolveImportConflicts(externals) { var moduleImports = {}; var usedNames = new Set(); var nameMapping = {}; var seenImports = new Set(); // First pass: collect all imports and resolve naming conflicts for (var _i = 0, _Object$entries = Object.entries(externals); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), modulePath = _Object$entries$_i[0], importItems = _Object$entries$_i[1]; if (!moduleImports[modulePath]) { moduleImports[modulePath] = { named: [], namespace: [] }; } var _iterator = _createForOfIteratorHelper(importItems), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var _step$value = _step.value, originalName = _step$value.name, type = _step$value.type, isType = _step$value.isType; // Skip type-only imports and empty names if (isType || !originalName.trim()) { continue; } var importKey = "".concat(modulePath, ":").concat(originalName, ":").concat(type); // Skip duplicates (this handles the duplicate React namespace import issue) if (seenImports.has(importKey)) { continue; } seenImports.add(importKey); var uniqueName = generateUniqueImportName(originalName, modulePath, type, usedNames); nameMapping[importKey] = uniqueName; usedNames.add(uniqueName); if (type === 'default') { moduleImports[modulePath]["default"] = uniqueName; } else if (type === 'named') { moduleImports[modulePath].named.push({ original: originalName, unique: uniqueName }); } else if (type === 'namespace') { moduleImports[modulePath].namespace.push(uniqueName); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } // Second pass: generate consolidated import statements and externals mappings var imports = []; var exportMappings = []; var _loop = function _loop() { var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2), modulePath = _Object$entries2$_i[0], moduleImport = _Object$entries2$_i[1]; var importParts = []; // Add default import if (moduleImport["default"]) { importParts.push(moduleImport["default"]); } // Add named imports (consolidated into one statement) if (moduleImport.named.length > 0) { var namedImports = moduleImport.named.map(function (_ref) { var original = _ref.original, unique = _ref.unique; return original === unique ? original : "".concat(original, " as ").concat(unique); }).join(', '); importParts.push("{ ".concat(namedImports, " }")); } // Generate import statement if (importParts.length > 0) { imports.push("import ".concat(importParts.join(', '), " from '").concat(modulePath, "';")); } // Add namespace imports (separate statements as they can't be combined) var _iterator2 = _createForOfIteratorHelper(moduleImport.namespace), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var namespaceName = _step2.value; imports.push("import * as ".concat(namespaceName, " from '").concat(modulePath, "';")); } // Generate single consolidated export mapping for this module } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } var exportParts = []; // Add default export if (moduleImport["default"]) { exportParts.push("default: ".concat(moduleImport["default"])); } // Add named exports moduleImport.named.forEach(function (_ref2) { var original = _ref2.original, unique = _ref2.unique; if (original === unique) { exportParts.push(original); } else { exportParts.push("".concat(original, ": ").concat(unique)); } }); // Add namespace exports moduleImport.namespace.forEach(function (namespaceName) { exportParts.push(namespaceName); }); // Only add export mapping if there are exports if (exportParts.length > 0) { // Check if we have only a single namespace export (no default, no named) var isOnlyNamespaceExport = exportParts.length === 1 && moduleImport.namespace.length === 1 && moduleImport["default"] === undefined && moduleImport.named.length === 0; if (isOnlyNamespaceExport) { // Single namespace export - use direct assignment (e.g., 'react': React) exportMappings.push("'".concat(modulePath, "': ").concat(exportParts[0])); } else { // All other cases - use object syntax to ensure consistency exportMappings.push("'".concat(modulePath, "': { ").concat(exportParts.join(', '), " }")); } } }; for (var _i2 = 0, _Object$entries2 = Object.entries(moduleImports); _i2 < _Object$entries2.length; _i2++) { _loop(); } return { imports: imports, exportMappings: exportMappings, nameMapping: nameMapping }; } /** * Generates the content for the CodeExternalsProvider file */ export function generateExternalsProviderContent(externals) { var _resolveImportConflic = resolveImportConflicts(externals), imports = _resolveImportConflic.imports, exportMappings = _resolveImportConflic.exportMappings; var importStatements = imports.length > 0 ? "".concat(imports.join('\n'), "\n") : ''; // Handle empty externals case var externalsContent = exportMappings.length > 0 ? "\n".concat(exportMappings.map(function (mapping) { return " ".concat(mapping); }).join(',\n'), "\n ") : ' '; // Two spaces for empty object formatting (to match test expectation: "{ }") // Only import React namespace when there are actually imports AND React is not already imported var hasReactImport = imports.some(function (imp) { return imp.includes("from 'react'"); }); var reactImport = imports.length > 0 && !hasReactImport ? "import * as React from 'react';\n" : ''; // Only import CodeExternalsContext if it's not already specifically imported as a named import var hasCodeExternalsContextImport = imports.some(function (imp) { return imp.includes("from '@mui/internal-docs-infra/CodeExternalsContext'") && imp.includes('{ CodeExternalsContext'); }); var codeExternalsContextImport = !hasCodeExternalsContextImport ? "import { CodeExternalsContext } from '@mui/internal-docs-infra/CodeExternalsContext';\n" : ''; return "'use client';\n\n".concat(reactImport).concat(importStatements).concat(codeExternalsContextImport, "\nconst externals = {").concat(externalsContent, "};\n\nexport function CodeExternalsProvider({ children }: { children: React.ReactNode }) {\n return (\n <CodeExternalsContext.Provider value={{ externals }}>\n {children}\n </CodeExternalsContext.Provider>\n );\n}\n"); } /** * Creates externals provider file information. * Returns the filename, content, and relative path for import. * If no externals exist, returns undefined. */ export function createExternalsProvider(externals, resourcePath) { var _resourcePath$split$p; // If no externals exist, don't create a provider if (Object.keys(externals).length === 0) { return undefined; } // Generate a unique filename for the externals provider var resourceName = resourcePath.replace(/\.[^/.]+$/, ''); // Remove extension var externalsFileName = "".concat(resourceName, ".externals.tsx"); // Extract just the filename from the full path for the relative import var basename = ((_resourcePath$split$p = resourcePath.split('/').pop()) == null ? void 0 : _resourcePath$split$p.replace(/\.[^/.]+$/, '')) || 'demo'; var relativeFileName = "".concat(basename, ".externals.tsx"); // Generate the externals provider content using combined externals var externalsProviderContent = generateExternalsProviderContent(externals); // Return the file information for the caller to handle emission return { fileName: externalsFileName, content: externalsProviderContent, relativePath: "./".concat(relativeFileName) }; }